mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Compare commits
	
		
			105 Commits
		
	
	
		
			osmith/rpm
			...
			laforge/si
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8e22379d7d | ||
| 
						 | 
					1bc597c752 | ||
| 
						 | 
					19c430feba | ||
| 
						 | 
					3ba409558e | ||
| 
						 | 
					60be627557 | ||
| 
						 | 
					8cfe7df3f1 | ||
| 
						 | 
					ba94b6d7be | ||
| 
						 | 
					30e01355f6 | ||
| 
						 | 
					06624e13d4 | ||
| 
						 | 
					19539866e5 | ||
| 
						 | 
					1dc2dcebbf | ||
| 
						 | 
					6049a63d1d | ||
| 
						 | 
					3ef8e76534 | ||
| 
						 | 
					fbf07f3f69 | ||
| 
						 | 
					de133113a0 | ||
| 
						 | 
					6d0a59a1bf | ||
| 
						 | 
					2491401932 | ||
| 
						 | 
					fbbe8f2f98 | ||
| 
						 | 
					71d42e778a | ||
| 
						 | 
					8a2a1b22fe | ||
| 
						 | 
					a790f0c082 | ||
| 
						 | 
					0ab152b2c6 | ||
| 
						 | 
					2741d6bb0e | ||
| 
						 | 
					74d0e5c318 | ||
| 
						 | 
					c4ef4a21c6 | ||
| 
						 | 
					ee2f33bf9a | ||
| 
						 | 
					531470a0ca | ||
| 
						 | 
					9dc73593a3 | ||
| 
						 | 
					ae6858bddf | ||
| 
						 | 
					99d4d368e8 | ||
| 
						 | 
					8667d5169d | ||
| 
						 | 
					1add5a53cb | ||
| 
						 | 
					729bf3e45a | ||
| 
						 | 
					2f34b53b5b | ||
| 
						 | 
					ad79f9eb99 | ||
| 
						 | 
					9e494e67c7 | ||
| 
						 | 
					5322473d04 | ||
| 
						 | 
					c57ad7ff9a | ||
| 
						 | 
					c59b5c533d | ||
| 
						 | 
					0653cc8a7c | ||
| 
						 | 
					246233d0d4 | ||
| 
						 | 
					a910a81b7c | ||
| 
						 | 
					c8acee2234 | ||
| 
						 | 
					55863e42c1 | ||
| 
						 | 
					6177cae2a2 | ||
| 
						 | 
					6af3ccf65d | ||
| 
						 | 
					03cb5f3397 | ||
| 
						 | 
					113141d4f9 | ||
| 
						 | 
					993ea6be7a | ||
| 
						 | 
					889fe7f203 | ||
| 
						 | 
					efd09d0b77 | ||
| 
						 | 
					ffbc618a13 | ||
| 
						 | 
					563ffc51b5 | ||
| 
						 | 
					51b42ff2e1 | ||
| 
						 | 
					7a755be4c2 | ||
| 
						 | 
					06ea49159e | ||
| 
						 | 
					869b21c869 | ||
| 
						 | 
					37a808c5a5 | ||
| 
						 | 
					24b8c0ce92 | ||
| 
						 | 
					fe67e094ad | ||
| 
						 | 
					fbcf39976e | ||
| 
						 | 
					4863591c23 | ||
| 
						 | 
					827da2c867 | ||
| 
						 | 
					efe1571b7b | ||
| 
						 | 
					6521fc0695 | ||
| 
						 | 
					f5531845bc | ||
| 
						 | 
					13fae78b32 | ||
| 
						 | 
					b7d395d83a | ||
| 
						 | 
					6fbbeec064 | ||
| 
						 | 
					0ffa3bdc45 | ||
| 
						 | 
					ca8639dc05 | ||
| 
						 | 
					8d6a193c1a | ||
| 
						 | 
					58a1ba85c7 | ||
| 
						 | 
					b0c05aa3a9 | ||
| 
						 | 
					0996a1e4ae | ||
| 
						 | 
					7e9ddc9904 | ||
| 
						 | 
					04bbb9de3e | ||
| 
						 | 
					bea56788cb | ||
| 
						 | 
					48bcc2ee12 | ||
| 
						 | 
					080935a8c7 | ||
| 
						 | 
					a466f57007 | ||
| 
						 | 
					41f77d8018 | ||
| 
						 | 
					e674345e29 | ||
| 
						 | 
					3f8139c55f | ||
| 
						 | 
					98c09b3f30 | ||
| 
						 | 
					7462b95829 | ||
| 
						 | 
					7a64182f9a | ||
| 
						 | 
					d19de2ee80 | ||
| 
						 | 
					08eb9352ab | ||
| 
						 | 
					0b79d21c7f | ||
| 
						 | 
					bce5f29265 | ||
| 
						 | 
					3d5a2dd19f | ||
| 
						 | 
					7f90ddb519 | ||
| 
						 | 
					c66ab2c4c3 | ||
| 
						 | 
					f53796c1fe | ||
| 
						 | 
					14b27a8893 | ||
| 
						 | 
					21be42abed | ||
| 
						 | 
					2d681fd84c | ||
| 
						 | 
					c39b1bffec | ||
| 
						 | 
					62612e8575 | ||
| 
						 | 
					af932ce3bc | ||
| 
						 | 
					265b0a8045 | ||
| 
						 | 
					74390c521e | ||
| 
						 | 
					abfb858f0c | ||
| 
						 | 
					6500d72aaf | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -61,3 +61,5 @@ doc/manuals/generated/
 | 
				
			|||||||
doc/manuals/osmomsc-usermanual.xml
 | 
					doc/manuals/osmomsc-usermanual.xml
 | 
				
			||||||
doc/manuals/common
 | 
					doc/manuals/common
 | 
				
			||||||
doc/manuals/build
 | 
					doc/manuals/build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contrib/osmo-mgw.spec
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -9,10 +9,10 @@ AM_CPPFLAGS = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SUBDIRS = \
 | 
					SUBDIRS = \
 | 
				
			||||||
	doc \
 | 
					 | 
				
			||||||
	include \
 | 
						include \
 | 
				
			||||||
	src \
 | 
						src \
 | 
				
			||||||
	tests \
 | 
						tests \
 | 
				
			||||||
 | 
						doc \
 | 
				
			||||||
	contrib \
 | 
						contrib \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,7 +22,13 @@ pkgconfig_DATA = \
 | 
				
			|||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BUILT_SOURCES = $(top_srcdir)/.version
 | 
					BUILT_SOURCES = $(top_srcdir)/.version
 | 
				
			||||||
EXTRA_DIST = git-version-gen osmoappdesc.py .version
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 | 
						     .version \
 | 
				
			||||||
 | 
						     contrib/osmo-mgw.spec.in \
 | 
				
			||||||
 | 
						     debian \
 | 
				
			||||||
 | 
						     git-version-gen \
 | 
				
			||||||
 | 
						     osmoappdesc.py \
 | 
				
			||||||
 | 
						     $(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
 | 
					AM_DISTCHECK_CONFIGURE_FLAGS = \
 | 
				
			||||||
	--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
 | 
						--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,3 +24,5 @@
 | 
				
			|||||||
# If any interfaces have been removed or changed since the last public release, a=0.
 | 
					# If any interfaces have been removed or changed since the last public release, a=0.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#library		what		description / commit summary line
 | 
					#library		what		description / commit summary line
 | 
				
			||||||
 | 
					osmo-mgw        update osmo-gsm-manuals dependency to > 0.3.0 for vty_cpu_sched.adoc include
 | 
				
			||||||
 | 
					libosmo-mgcp-client     mgcp_response, mgcp_conn_peer   struct size change, breaks ABI
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								configure.ac
									
									
									
									
									
								
							@@ -47,11 +47,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
 | 
				
			|||||||
AC_SUBST(LIBRARY_DLSYM)
 | 
					AC_SUBST(LIBRARY_DLSYM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)
 | 
				
			||||||
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.0.0)
 | 
				
			||||||
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -209,4 +211,5 @@ AC_OUTPUT(
 | 
				
			|||||||
    doc/manuals/Makefile
 | 
					    doc/manuals/Makefile
 | 
				
			||||||
    contrib/Makefile
 | 
					    contrib/Makefile
 | 
				
			||||||
    contrib/systemd/Makefile
 | 
					    contrib/systemd/Makefile
 | 
				
			||||||
 | 
					    contrib/osmo-mgw.spec
 | 
				
			||||||
    Makefile)
 | 
					    Makefile)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Name:           osmo-mgw
 | 
					Name:           osmo-mgw
 | 
				
			||||||
Version:        1.7.0.13
 | 
					Version:        @VERSION@
 | 
				
			||||||
Release:        0
 | 
					Release:        0
 | 
				
			||||||
Summary:        Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					Summary:        Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
				
			||||||
License:        AGPL-3.0-or-later AND GPL-2.0-or-later
 | 
					License:        AGPL-3.0-or-later AND GPL-2.0-or-later
 | 
				
			||||||
@@ -26,13 +26,17 @@ Source:         %{name}-%{version}.tar.xz
 | 
				
			|||||||
BuildRequires:  automake >= 1.9
 | 
					BuildRequires:  automake >= 1.9
 | 
				
			||||||
BuildRequires:  libtool >= 2
 | 
					BuildRequires:  libtool >= 2
 | 
				
			||||||
BuildRequires:  pkgconfig >= 0.20
 | 
					BuildRequires:  pkgconfig >= 0.20
 | 
				
			||||||
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
 | 
					%endif
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 0.6.0
 | 
					BuildRequires:  pkgconfig(libosmo-netif) >= 0.6.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.0.0
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.0.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.1.0
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.1.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.0.0
 | 
					BuildRequires:  pkgconfig(libosmogsm) >= 1.0.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.0.0
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.0.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.0.0
 | 
					BuildRequires:  pkgconfig(libosmocoding) >= 1.0.0
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libosmoabis) >= 1.0.0
 | 
				
			||||||
 | 
					BuildRequires:  pkgconfig(libosmotrau) >= 1.0.0
 | 
				
			||||||
%{?systemd_requires}
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description
 | 
					%description
 | 
				
			||||||
@@ -88,6 +92,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
%post   -n libosmo-mgcp-client6 -p /sbin/ldconfig
 | 
					%post   -n libosmo-mgcp-client6 -p /sbin/ldconfig
 | 
				
			||||||
%postun -n libosmo-mgcp-client6 -p /sbin/ldconfig
 | 
					%postun -n libosmo-mgcp-client6 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
%preun
 | 
					%preun
 | 
				
			||||||
%service_del_preun osmo-mgw.service
 | 
					%service_del_preun osmo-mgw.service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,6 +105,7 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
%post
 | 
					%post
 | 
				
			||||||
%service_add_post osmo-mgw.service
 | 
					%service_add_post osmo-mgw.service
 | 
				
			||||||
 | 
					%endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files
 | 
					%files
 | 
				
			||||||
%license COPYING
 | 
					%license COPYING
 | 
				
			||||||
@@ -106,10 +113,11 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
%dir %{_docdir}/%{name}/examples
 | 
					%dir %{_docdir}/%{name}/examples
 | 
				
			||||||
%dir %{_docdir}/%{name}/examples/osmo-mgw
 | 
					%dir %{_docdir}/%{name}/examples/osmo-mgw
 | 
				
			||||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
 | 
					%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
 | 
				
			||||||
 | 
					%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
 | 
				
			||||||
%{_bindir}/osmo-mgw
 | 
					%{_bindir}/osmo-mgw
 | 
				
			||||||
%{_unitdir}/osmo-mgw.service
 | 
					%{_unitdir}/osmo-mgw.service
 | 
				
			||||||
%dir %{_sysconfdir}/osmocom
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
%config %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client6
 | 
					%files -n libosmo-mgcp-client6
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.6*
 | 
					%{_libdir}/libosmo-mgcp-client.so.6*
 | 
				
			||||||
							
								
								
									
										11
									
								
								contrib/simcom2rtp/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								contrib/simcom2rtp/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					CFLAGS:= -O2 -g -Wall $(shell pkg-config --cflags libosmocore libosmotrau)
 | 
				
			||||||
 | 
					LIBS:= $(shell pkg-config --libs libosmocore libosmotrau)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: osmo-simcom2rtp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-simcom2rtp: g711.o g711_table.o simcom2rtp.o
 | 
				
			||||||
 | 
						$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%.o: %.c
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) -o $@ -c $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										313
									
								
								contrib/simcom2rtp/g711.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								contrib/simcom2rtp/g711.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This source code is a product of Sun Microsystems, Inc. and is provided
 | 
				
			||||||
 | 
					 * for unrestricted use.  Users may copy or modify this source code without
 | 
				
			||||||
 | 
					 * charge.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
 | 
				
			||||||
 | 
					 * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 | 
				
			||||||
 | 
					 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sun source code is provided with no support and without any obligation on
 | 
				
			||||||
 | 
					 * the part of Sun Microsystems, Inc. to assist in its use, correction,
 | 
				
			||||||
 | 
					 * modification or enhancement.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 | 
				
			||||||
 | 
					 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
 | 
				
			||||||
 | 
					 * OR ANY PART THEREOF.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 | 
				
			||||||
 | 
					 * or profits or other special, indirect and consequential damages, even if
 | 
				
			||||||
 | 
					 * Sun has been advised of the possibility of such damages.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sun Microsystems, Inc.
 | 
				
			||||||
 | 
					 * 2550 Garcia Avenue
 | 
				
			||||||
 | 
					 * Mountain View, California  94043
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * December 30, 1994:
 | 
				
			||||||
 | 
					 * Functions linear2alaw, linear2ulaw have been updated to correctly
 | 
				
			||||||
 | 
					 * convert unquantized 16 bit values.
 | 
				
			||||||
 | 
					 * Tables for direct u- to A-law and A- to u-law conversions have been
 | 
				
			||||||
 | 
					 * corrected.
 | 
				
			||||||
 | 
					 * Borge Lindberg, Center for PersonKommunikation, Aalborg University.
 | 
				
			||||||
 | 
					 * bli@cpk.auc.dk
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Downloaded from comp.speech site in Cambridge.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * g711.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * u-law, A-law and linear PCM conversions.
 | 
				
			||||||
 | 
					 * Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.c
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
 | 
				
			||||||
 | 
					#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
 | 
				
			||||||
 | 
					#define	NSEGS		(8)		/* Number of A-law segments. */
 | 
				
			||||||
 | 
					#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
 | 
				
			||||||
 | 
					#define	SEG_MASK	(0x70)		/* Segment field mask. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static short seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
 | 
				
			||||||
 | 
								    0x1FF, 0x3FF, 0x7FF, 0xFFF};
 | 
				
			||||||
 | 
					static short seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
 | 
				
			||||||
 | 
								    0x3FF, 0x7FF, 0xFFF, 0x1FFF};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* copy from CCITT G.711 specifications */
 | 
				
			||||||
 | 
					unsigned char _u2a[128] = {			/* u- to A-law conversions */
 | 
				
			||||||
 | 
						1,	1,	2,	2,	3,	3,	4,	4,
 | 
				
			||||||
 | 
						5,	5,	6,	6,	7,	7,	8,	8,
 | 
				
			||||||
 | 
						9,	10,	11,	12,	13,	14,	15,	16,
 | 
				
			||||||
 | 
						17,	18,	19,	20,	21,	22,	23,	24,
 | 
				
			||||||
 | 
						25,	27,	29,	31,	33,	34,	35,	36,
 | 
				
			||||||
 | 
						37,	38,	39,	40,	41,	42,	43,	44,
 | 
				
			||||||
 | 
						46,	48,	49,	50,	51,	52,	53,	54,
 | 
				
			||||||
 | 
						55,	56,	57,	58,	59,	60,	61,	62,
 | 
				
			||||||
 | 
						64,	65,	66,	67,	68,	69,	70,	71,
 | 
				
			||||||
 | 
						72,	73,	74,	75,	76,	77,	78,	79,
 | 
				
			||||||
 | 
					/* corrected:
 | 
				
			||||||
 | 
						81,	82,	83,	84,	85,	86,	87,	88, 
 | 
				
			||||||
 | 
					   should be: */
 | 
				
			||||||
 | 
						80,	82,	83,	84,	85,	86,	87,	88,
 | 
				
			||||||
 | 
						89,	90,	91,	92,	93,	94,	95,	96,
 | 
				
			||||||
 | 
						97,	98,	99,	100,	101,	102,	103,	104,
 | 
				
			||||||
 | 
						105,	106,	107,	108,	109,	110,	111,	112,
 | 
				
			||||||
 | 
						113,	114,	115,	116,	117,	118,	119,	120,
 | 
				
			||||||
 | 
						121,	122,	123,	124,	125,	126,	127,	128};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned char _a2u[128] = {			/* A- to u-law conversions */
 | 
				
			||||||
 | 
						1,	3,	5,	7,	9,	11,	13,	15,
 | 
				
			||||||
 | 
						16,	17,	18,	19,	20,	21,	22,	23,
 | 
				
			||||||
 | 
						24,	25,	26,	27,	28,	29,	30,	31,
 | 
				
			||||||
 | 
						32,	32,	33,	33,	34,	34,	35,	35,
 | 
				
			||||||
 | 
						36,	37,	38,	39,	40,	41,	42,	43,
 | 
				
			||||||
 | 
						44,	45,	46,	47,	48,	48,	49,	49,
 | 
				
			||||||
 | 
						50,	51,	52,	53,	54,	55,	56,	57,
 | 
				
			||||||
 | 
						58,	59,	60,	61,	62,	63,	64,	64,
 | 
				
			||||||
 | 
						65,	66,	67,	68,	69,	70,	71,	72,
 | 
				
			||||||
 | 
					/* corrected:
 | 
				
			||||||
 | 
						73,	74,	75,	76,	77,	78,	79,	79,
 | 
				
			||||||
 | 
					   should be: */
 | 
				
			||||||
 | 
						73,	74,	75,	76,	77,	78,	79,	80,
 | 
				
			||||||
 | 
						80,	81,	82,	83,	84,	85,	86,	87,
 | 
				
			||||||
 | 
						88,	89,	90,	91,	92,	93,	94,	95,
 | 
				
			||||||
 | 
						96,	97,	98,	99,	100,	101,	102,	103,
 | 
				
			||||||
 | 
						104,	105,	106,	107,	108,	109,	110,	111,
 | 
				
			||||||
 | 
						112,	113,	114,	115,	116,	117,	118,	119,
 | 
				
			||||||
 | 
						120,	121,	122,	123,	124,	125,	126,	127};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static short search(
 | 
				
			||||||
 | 
					   short val,
 | 
				
			||||||
 | 
					   short *table,
 | 
				
			||||||
 | 
					   short size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short i;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   for (i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					      if (val <= *table++)
 | 
				
			||||||
 | 
						 return (i);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return (size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *		Linear Input Code	Compressed Code
 | 
				
			||||||
 | 
					 *	------------------------	---------------
 | 
				
			||||||
 | 
					 *	0000000wxyza			000wxyz
 | 
				
			||||||
 | 
					 *	0000001wxyza			001wxyz
 | 
				
			||||||
 | 
					 *	000001wxyzab			010wxyz
 | 
				
			||||||
 | 
					 *	00001wxyzabc			011wxyz
 | 
				
			||||||
 | 
					 *	0001wxyzabcd			100wxyz
 | 
				
			||||||
 | 
					 *	001wxyzabcde			101wxyz
 | 
				
			||||||
 | 
					 *	01wxyzabcdef			110wxyz
 | 
				
			||||||
 | 
					 *	1wxyzabcdefg			111wxyz
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For further information see John C. Bellamy's Digital Telephony, 1982,
 | 
				
			||||||
 | 
					 * John Wiley & Sons, pps 98-111 and 472-476.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					linear2alaw(short pcm_val)	/* 2's complement (16-bit range) */
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short	 mask;
 | 
				
			||||||
 | 
					   short	 seg;
 | 
				
			||||||
 | 
					   unsigned char aval;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   pcm_val = pcm_val >> 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if (pcm_val >= 0) {
 | 
				
			||||||
 | 
					      mask = 0xD5;		/* sign (7th) bit = 1 */
 | 
				
			||||||
 | 
					   } else {
 | 
				
			||||||
 | 
					      mask = 0x55;		/* sign bit = 0 */
 | 
				
			||||||
 | 
					      pcm_val = -pcm_val - 1;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Convert the scaled magnitude to segment number. */
 | 
				
			||||||
 | 
					   seg = search(pcm_val, seg_aend, 8);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Combine the sign, segment, and quantization bits. */
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   if (seg >= 8)		/* out of range, return maximum value. */
 | 
				
			||||||
 | 
					      return (unsigned char) (0x7F ^ mask);
 | 
				
			||||||
 | 
					   else {
 | 
				
			||||||
 | 
					      aval = (unsigned char) seg << SEG_SHIFT;
 | 
				
			||||||
 | 
					      if (seg < 2)
 | 
				
			||||||
 | 
						 aval |= (pcm_val >> 1) & QUANT_MASK;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
						 aval |= (pcm_val >> seg) & QUANT_MASK;
 | 
				
			||||||
 | 
					      return (aval ^ mask);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * alaw2linear() - Convert an A-law value to 16-bit linear PCM
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					short
 | 
				
			||||||
 | 
					alaw2linear(
 | 
				
			||||||
 | 
					   unsigned char	a_val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short t;
 | 
				
			||||||
 | 
					   short seg;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   a_val ^= 0x55;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   t = (a_val & QUANT_MASK) << 4;
 | 
				
			||||||
 | 
					   seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
 | 
				
			||||||
 | 
					   switch (seg) {
 | 
				
			||||||
 | 
					   case 0:
 | 
				
			||||||
 | 
					      t += 8;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					   case 1:
 | 
				
			||||||
 | 
					      t += 0x108;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					   default:
 | 
				
			||||||
 | 
					      t += 0x108;
 | 
				
			||||||
 | 
					      t <<= seg - 1;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return ((a_val & SIGN_BIT) ? t : -t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	BIAS		(0x84)		/* Bias for linear code. */
 | 
				
			||||||
 | 
					#define CLIP            8159
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* linear2ulaw() - Convert a linear PCM value to u-law
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* In order to simplify the encoding process, the original linear magnitude
 | 
				
			||||||
 | 
					* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
 | 
				
			||||||
 | 
					* (33 - 8191). The result can be seen in the following encoding table:
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*	Biased Linear Input Code	Compressed Code
 | 
				
			||||||
 | 
					*	------------------------	---------------
 | 
				
			||||||
 | 
					*	00000001wxyza			000wxyz
 | 
				
			||||||
 | 
					*	0000001wxyzab			001wxyz
 | 
				
			||||||
 | 
					*	000001wxyzabc			010wxyz
 | 
				
			||||||
 | 
					*	00001wxyzabcd			011wxyz
 | 
				
			||||||
 | 
					*	0001wxyzabcde			100wxyz
 | 
				
			||||||
 | 
					*	001wxyzabcdef			101wxyz
 | 
				
			||||||
 | 
					*	01wxyzabcdefg			110wxyz
 | 
				
			||||||
 | 
					*	1wxyzabcdefgh			111wxyz
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* Each biased linear code has a leading 1 which identifies the segment
 | 
				
			||||||
 | 
					* number. The value of the segment number is equal to 7 minus the number
 | 
				
			||||||
 | 
					* of leading 0's. The quantization interval is directly available as the
 | 
				
			||||||
 | 
					* four bits wxyz.  * The trailing bits (a - h) are ignored.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* Ordinarily the complement of the resulting code word is used for
 | 
				
			||||||
 | 
					* transmission, and so the code word is complemented before it is returned.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* For further information see John C. Bellamy's Digital Telephony, 1982,
 | 
				
			||||||
 | 
					* John Wiley & Sons, pps 98-111 and 472-476.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					linear2ulaw(
 | 
				
			||||||
 | 
					   short pcm_val)	/* 2's complement (16-bit range) */
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short         mask;
 | 
				
			||||||
 | 
					   short	 seg;
 | 
				
			||||||
 | 
					   unsigned char uval;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Get the sign and the magnitude of the value. */
 | 
				
			||||||
 | 
					   pcm_val = pcm_val >> 2;
 | 
				
			||||||
 | 
					   if (pcm_val < 0) {
 | 
				
			||||||
 | 
					      pcm_val = -pcm_val;
 | 
				
			||||||
 | 
					      mask = 0x7F;
 | 
				
			||||||
 | 
					   } else {
 | 
				
			||||||
 | 
					      mask = 0xFF;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if ( pcm_val > CLIP ) pcm_val = CLIP;		/* clip the magnitude */
 | 
				
			||||||
 | 
					   pcm_val += (BIAS >> 2);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Convert the scaled magnitude to segment number. */
 | 
				
			||||||
 | 
					   seg = search(pcm_val, seg_uend, 8);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /*
 | 
				
			||||||
 | 
					   * Combine the sign, segment, quantization bits;
 | 
				
			||||||
 | 
					   * and complement the code word.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					   if (seg >= 8)		/* out of range, return maximum value. */
 | 
				
			||||||
 | 
					      return (unsigned char) (0x7F ^ mask);
 | 
				
			||||||
 | 
					   else {
 | 
				
			||||||
 | 
					      uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
 | 
				
			||||||
 | 
					      return (uval ^ mask);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * First, a biased linear code is derived from the code word. An unbiased
 | 
				
			||||||
 | 
					 * output can then be obtained by subtracting 33 from the biased code.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that this function expects to be passed the complement of the
 | 
				
			||||||
 | 
					 * original code word. This is in keeping with ISDN conventions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					short
 | 
				
			||||||
 | 
					ulaw2linear(
 | 
				
			||||||
 | 
					   unsigned char	u_val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short t;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Complement to obtain normal u-law value. */
 | 
				
			||||||
 | 
					   u_val = ~u_val;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /*
 | 
				
			||||||
 | 
					    * Extract and bias the quantization bits. Then
 | 
				
			||||||
 | 
					    * shift up by the segment number and subtract out the bias.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   t = ((u_val & QUANT_MASK) << 3) + BIAS;
 | 
				
			||||||
 | 
					   t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A-law to u-law conversion */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					alaw2ulaw(
 | 
				
			||||||
 | 
					   unsigned char	aval)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   aval &= 0xff;
 | 
				
			||||||
 | 
					   return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
 | 
				
			||||||
 | 
						   (0x7F ^ _a2u[aval ^ 0x55]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* u-law to A-law conversion */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					ulaw2alaw(
 | 
				
			||||||
 | 
					   unsigned char	uval)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   uval &= 0xff;
 | 
				
			||||||
 | 
					   return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
 | 
				
			||||||
 | 
								   (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ---------- end of g711.c ----------------------------------------------------- */
 | 
				
			||||||
							
								
								
									
										27
									
								
								contrib/simcom2rtp/g711.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contrib/simcom2rtp/g711.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * g711.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * u-law, A-law and linear PCM conversions.
 | 
				
			||||||
 | 
					 * Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.h
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _G711_H_
 | 
				
			||||||
 | 
					#define _G711_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned char	linear2alaw(short pcm_val);
 | 
				
			||||||
 | 
					short		    alaw2linear(unsigned char a_val);
 | 
				
			||||||
 | 
					unsigned char	linear2ulaw(short pcm_val);
 | 
				
			||||||
 | 
					short		    ulaw2linear(unsigned char u_val);
 | 
				
			||||||
 | 
					unsigned char	alaw2ulaw(unsigned char aval);
 | 
				
			||||||
 | 
					unsigned char	ulaw2alaw(unsigned char uval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _G711_H_ */
 | 
				
			||||||
							
								
								
									
										102
									
								
								contrib/simcom2rtp/g711_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								contrib/simcom2rtp/g711_table.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					#ifndef G711_TABLE_H
 | 
				
			||||||
 | 
					#define G711_TABLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 16384 entries per table (16 bit) */
 | 
				
			||||||
 | 
					unsigned char linear_to_alaw[65536];
 | 
				
			||||||
 | 
					unsigned char linear_to_ulaw[65536];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 16384 entries per table (8 bit) */
 | 
				
			||||||
 | 
					unsigned short alaw_to_linear[256];
 | 
				
			||||||
 | 
					unsigned short ulaw_to_linear[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void build_linear_to_xlaw_table(unsigned char *linear_to_xlaw,
 | 
				
			||||||
 | 
					                                       unsigned char (*linear2xlaw)(short))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i<65536;i++){
 | 
				
			||||||
 | 
					        linear_to_xlaw[i] = linear2xlaw((short) i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void build_xlaw_to_linear_table(unsigned short *xlaw_to_linear,
 | 
				
			||||||
 | 
					                                       short (*xlaw2linear)(unsigned char))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i<256;i++){
 | 
				
			||||||
 | 
					        xlaw_to_linear[i] = (unsigned short) xlaw2linear(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void pcm16_to_xlaw(unsigned char *linear_to_xlaw, int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    const unsigned short *s_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s_samples = (const unsigned short *)src_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i < src_length / 2; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        dst_samples[i] = linear_to_xlaw[s_samples[i]];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void xlaw_to_pcm16(unsigned short *xlaw_to_linear, int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    unsigned char *s_samples;
 | 
				
			||||||
 | 
					    unsigned short *d_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s_samples = (unsigned char *) src_samples;
 | 
				
			||||||
 | 
					    d_samples = (unsigned short *)dst_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i < src_length; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        d_samples[i] = xlaw_to_linear[s_samples[i]];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_alaw(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pcm16_to_xlaw(linear_to_alaw, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_ulaw(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pcm16_to_xlaw(linear_to_ulaw, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void alaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    xlaw_to_pcm16(alaw_to_linear, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ulaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    xlaw_to_pcm16(ulaw_to_linear, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_alaw_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_linear_to_xlaw_table(linear_to_alaw, linear2alaw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_ulaw_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_linear_to_xlaw_table(linear_to_ulaw, linear2ulaw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void alaw_pcm16_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_xlaw_to_linear_table(alaw_to_linear, alaw2linear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ulaw_pcm16_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_xlaw_to_linear_table(ulaw_to_linear, ulaw2linear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // G711_TABLE_H
 | 
				
			||||||
							
								
								
									
										14
									
								
								contrib/simcom2rtp/g711_table.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								contrib/simcom2rtp/g711_table.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef G711_TABLE_H
 | 
				
			||||||
 | 
					#define G711_TABLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_alaw(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void pcm16_to_ulaw(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void alaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void ulaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_alaw_tableinit();
 | 
				
			||||||
 | 
					void pcm16_ulaw_tableinit();
 | 
				
			||||||
 | 
					void alaw_pcm16_tableinit();
 | 
				
			||||||
 | 
					void ulaw_pcm16_tableinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // G711_TABLE_H
 | 
				
			||||||
							
								
								
									
										218
									
								
								contrib/simcom2rtp/simcom2rtp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								contrib/simcom2rtp/simcom2rtp.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,218 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/serial.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/trau/osmo_ortp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RTP_PT_PCMU	0
 | 
				
			||||||
 | 
					#define RTP_PT_PCMA	8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct modem_state {
 | 
				
			||||||
 | 
						struct osmo_fd data_fd;
 | 
				
			||||||
 | 
						struct osmo_rtp_socket *rtp;
 | 
				
			||||||
 | 
						/* queue of linear PCM audio in RTP -> modem direction */
 | 
				
			||||||
 | 
						struct llist_head rtp2modem;
 | 
				
			||||||
 | 
						/* message buffer used if samples insufficient for next RTP frame were received */
 | 
				
			||||||
 | 
						struct msgb *modem2rtp;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *g_tall_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* call-back on received RTP data */
 | 
				
			||||||
 | 
					static void ortp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *payload,
 | 
				
			||||||
 | 
								unsigned int payload_len, uint16_t seq_nr, uint32_t timestamp, bool marker)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* we received a RTP frame */
 | 
				
			||||||
 | 
						struct modem_state *ms = rs->priv;
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc(payload_len*2, "RTP Rx");
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int16_t *out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out = (int16_t *) msgb_put(msg, payload_len*2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload_len != 160) {
 | 
				
			||||||
 | 
							fprintf(stderr, "RTP payload length %d != 160, dropping\n", payload_len);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* convert from Alaw to linear PCM (160 -> 320 bytes) */
 | 
				
			||||||
 | 
						for (i = 0; i < payload_len; i++)
 | 
				
			||||||
 | 
							out[i] = alaw2linear(payload[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* append to the write queue */
 | 
				
			||||||
 | 
						msgb_enqueue(&ms->rtp2modem, msg);
 | 
				
			||||||
 | 
						ms->data_fd.when |= OSMO_FD_WRITE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void modem2rtp(struct modem_state *ms, const uint8_t *data, unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const int16_t *data16 = (const int16_t *)data;
 | 
				
			||||||
 | 
						unsigned int samples = len / 2;
 | 
				
			||||||
 | 
						unsigned int offset = 0;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* samples are always 16bit, we cannot read half a sample */
 | 
				
			||||||
 | 
						OSMO_ASSERT((len & 1) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* first complete any pending incomplete RTP frame */
 | 
				
			||||||
 | 
						if (ms->modem2rtp) {
 | 
				
			||||||
 | 
							struct msgb *msg = ms->modem2rtp;
 | 
				
			||||||
 | 
							unsigned int missing_samples = 160 - msgb_length(msg);
 | 
				
			||||||
 | 
							for (i = 0; i < missing_samples; i++) {
 | 
				
			||||||
 | 
								if (i >= samples)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								msgb_put_u8(msg, linear2alaw(data16[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							offset = i;
 | 
				
			||||||
 | 
							if (msgb_length(msg) == 160) {
 | 
				
			||||||
 | 
								osmo_rtp_send_frame_ext(ms->rtp, msgb_data(msg), msgb_length(msg), 160, false);
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* then send as many RTP frames as we have samples */
 | 
				
			||||||
 | 
						for (offset = offset; offset + 160 <= samples; offset += 160) {
 | 
				
			||||||
 | 
							uint8_t buf[160];
 | 
				
			||||||
 | 
							for (i = 0; i < sizeof(buf); i++)
 | 
				
			||||||
 | 
								buf[i] = linear2alaw(data16[offset + i]);
 | 
				
			||||||
 | 
							osmo_rtp_send_frame_ext(ms->rtp, buf, sizeof(buf), 160, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* store remainder in msgb */
 | 
				
			||||||
 | 
						if (offset < samples) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_alloc_c(ms, 160, "modem2rtp");
 | 
				
			||||||
 | 
							OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
							OSMO_ASSERT(len - offset < 160);
 | 
				
			||||||
 | 
							for (i = 0; i < len - offset; i++)
 | 
				
			||||||
 | 
								msgb_put_u8(msg, linear2alaw(data16[offset + i]));
 | 
				
			||||||
 | 
							ms->modem2rtp = msg;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* call back on file descriptor events of the modem DATA ttyUSB device */
 | 
				
			||||||
 | 
					static int modem_data_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct modem_state *ms = ofd->data;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (what & OSMO_FD_READ) {
 | 
				
			||||||
 | 
							/* SIM5360 USB AUDIO Application Note v1.01 states 1600 bytes every 100ms */
 | 
				
			||||||
 | 
							uint8_t rx_buf[1600];
 | 
				
			||||||
 | 
							rc = read(ofd->fd, rx_buf, sizeof(rx_buf));
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc > 0);
 | 
				
			||||||
 | 
							modem2rtp(ms, rx_buf, rc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (what & OSMO_FD_WRITE) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_dequeue(&ms->rtp2modem);
 | 
				
			||||||
 | 
							if (!msg)
 | 
				
			||||||
 | 
								ofd->when &= ~OSMO_FD_WRITE;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								/* SIM5300 USB AUDIO Application Note v1.01 states 640 bytes every 40ms;
 | 
				
			||||||
 | 
								 * we simply write every RTP frame individually (320 bytes every 20ms) */
 | 
				
			||||||
 | 
								rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
								if (rc != msgb_length(msg))
 | 
				
			||||||
 | 
									fprintf(stderr, "Short write: %d < %u\n", rc, msgb_length(msg));
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int modem_data_open(struct modem_state *ms, const char *basepath)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char fname[PATH_MAX+1];
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the assumption is that the caller provides something like
 | 
				
			||||||
 | 
						 * "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1" */
 | 
				
			||||||
 | 
						snprintf(fname, sizeof(fname), "%s.0-port0", basepath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd = osmo_serial_init(fname, 921600);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "failed to open device '%s': %s\n", fname, strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						osmo_fd_setup(&ms->data_fd, fd, OSMO_FD_READ, modem_data_fd_cb, ms, 0);
 | 
				
			||||||
 | 
						osmo_fd_register(&ms->data_fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct modem_state *modem_create(void *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct modem_state *ms = talloc_zero(ctx, struct modem_state);
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&ms->rtp2modem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms->rtp = osmo_rtp_socket_create(ms, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->rtp);
 | 
				
			||||||
 | 
						osmo_rtp_socket_set_pt(ms->rtp, RTP_PT_PCMA);
 | 
				
			||||||
 | 
						ms->rtp->priv = ms;
 | 
				
			||||||
 | 
						ms->rtp->rx_cb = ortp_rx_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_rtp_socket_bind(ms->rtp, "0.0.0.0", 1111);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_rtp_socket_connect(ms->rtp, "127.0.0.1", 2222);
 | 
				
			||||||
 | 
						//rc = osmo_rtp_socket_autoconnect(ms->rtp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_rtp_set_source_desc(ms->rtp, "cname", "simcom2rtp", NULL, NULL, NULL,
 | 
				
			||||||
 | 
									 "osmo-simcom2rtp", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_enable_null_tracking();
 | 
				
			||||||
 | 
						g_tall_ctx = talloc_named_const(NULL, 1, "simcom2rtp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(g_tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(g_tall_ctx, NULL);
 | 
				
			||||||
 | 
						osmo_fsm_log_timeouts(true);
 | 
				
			||||||
 | 
						osmo_fsm_log_addr(true);
 | 
				
			||||||
 | 
						//osmo_stats_init(g_tall_ctx);
 | 
				
			||||||
 | 
						osmo_rtp_init(g_tall_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct modem_state *ms = modem_create(g_tall_ctx);
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms);
 | 
				
			||||||
 | 
						rc = modem_data_open(ms, "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1");
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							osmo_select_main(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,13 +1,14 @@
 | 
				
			|||||||
Source: osmo-mgw
 | 
					Source: osmo-mgw
 | 
				
			||||||
Section: net
 | 
					Section: net
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Maintainer: Alexander Couzens <lynxis@fe80.eu>
 | 
					Maintainer: Osmocom team <openbsc@lists.osmocom.org>
 | 
				
			||||||
Build-Depends: debhelper (>=9),
 | 
					Build-Depends: debhelper (>=9),
 | 
				
			||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev,
 | 
					               libosmocore-dev (>= 1.4.0),
 | 
				
			||||||
               libosmo-netif-dev,
 | 
					               libosmo-netif-dev,
 | 
				
			||||||
 | 
					               libosmo-abis-dev,
 | 
				
			||||||
               osmo-gsm-manuals-dev
 | 
					               osmo-gsm-manuals-dev
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
					Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/osmo-mgw.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-mgw.install
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,4 @@ etc/osmocom/osmo-mgw.cfg
 | 
				
			|||||||
lib/systemd/system/osmo-mgw.service
 | 
					lib/systemd/system/osmo-mgw.service
 | 
				
			||||||
usr/bin/osmo-mgw
 | 
					usr/bin/osmo-mgw
 | 
				
			||||||
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw.cfg
 | 
					usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw.cfg
 | 
				
			||||||
 | 
					usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								doc/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								doc/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					!
 | 
				
			||||||
 | 
					! MGCP configuration example
 | 
				
			||||||
 | 
					!
 | 
				
			||||||
 | 
					e1_input
 | 
				
			||||||
 | 
					 e1_line 0 driver dahdi
 | 
				
			||||||
 | 
					 e1_line 0 port 0
 | 
				
			||||||
 | 
					mgcp
 | 
				
			||||||
 | 
					  bind ip 127.0.0.1
 | 
				
			||||||
 | 
					  rtp port-range 4002 16000
 | 
				
			||||||
 | 
					  rtp bind-ip 127.0.0.1
 | 
				
			||||||
 | 
					  rtp ip-probing
 | 
				
			||||||
 | 
					  rtp ip-tos 184
 | 
				
			||||||
 | 
					  bind port 2427
 | 
				
			||||||
 | 
					  sdp audio payload number 98
 | 
				
			||||||
 | 
					  sdp audio payload name GSM
 | 
				
			||||||
 | 
					  number endpoints 31
 | 
				
			||||||
 | 
					  loop 0
 | 
				
			||||||
 | 
					  force-realloc 1
 | 
				
			||||||
 | 
					  rtcp-omit
 | 
				
			||||||
 | 
					  rtp-patch ssrc
 | 
				
			||||||
 | 
					  rtp-patch timestamp
 | 
				
			||||||
 | 
					  trunk 1
 | 
				
			||||||
 | 
					   rtp keep-alive once
 | 
				
			||||||
 | 
					   no rtp keep-alive
 | 
				
			||||||
 | 
					   line 0
 | 
				
			||||||
@@ -13,6 +13,11 @@ if BUILD_MANUALS
 | 
				
			|||||||
  VTY_REFERENCE = osmomgw-vty-reference.xml
 | 
					  VTY_REFERENCE = osmomgw-vty-reference.xml
 | 
				
			||||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BUILT_REFERENCE_XML = $(builddir)/vty/mgw_vty_reference.xml
 | 
				
			||||||
 | 
					  $(builddir)/vty/mgw_vty_reference.xml: $(top_builddir)/src/osmo-mgw/osmo-mgw
 | 
				
			||||||
 | 
						mkdir -p $(builddir)/vty
 | 
				
			||||||
 | 
						$(top_builddir)/src/osmo-mgw/osmo-mgw --vty-ref-xml > $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  OSMO_REPOSITORY = osmo-mgw
 | 
					  OSMO_REPOSITORY = osmo-mgw
 | 
				
			||||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,8 @@ include::./common/chapters/osmux/osmux.adoc[]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//include::{srcdir}/chapters/counters.adoc[]
 | 
					//include::{srcdir}/chapters/counters.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/vty_cpu_sched.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/port_numbers.adoc[]
 | 
					include::./common/chapters/port_numbers.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/bibliography.adoc[]
 | 
					include::./common/chapters/bibliography.adoc[]
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -8,7 +8,6 @@ nobase_include_HEADERS = \
 | 
				
			|||||||
	osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp.h \
 | 
						osmocom/mgcp/mgcp.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_common.h \
 | 
						osmocom/mgcp/mgcp_common.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_internal.h \
 | 
					 | 
				
			||||||
	osmocom/mgcp/osmux.h \
 | 
						osmocom/mgcp/osmux.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,5 +7,10 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_sdp.h \
 | 
						mgcp_sdp.h \
 | 
				
			||||||
	mgcp_codec.h \
 | 
						mgcp_codec.h \
 | 
				
			||||||
	mgcp_ctrl.h \
 | 
						mgcp_ctrl.h \
 | 
				
			||||||
 | 
						mgcp_trunk.h \
 | 
				
			||||||
	debug.h \
 | 
						debug.h \
 | 
				
			||||||
 | 
						mgcp_ratectr.h \
 | 
				
			||||||
 | 
						mgcp_e1.h \
 | 
				
			||||||
 | 
						mgcp_network.h \
 | 
				
			||||||
 | 
						mgcp_protocol.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
/* Debug Areas of the code */
 | 
					/* Debug Areas of the code */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	DRTP,
 | 
						DRTP,
 | 
				
			||||||
 | 
						DE1,
 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
#include <osmocom/core/write_queue.h>
 | 
					#include <osmocom/core/write_queue.h>
 | 
				
			||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
@@ -34,6 +35,8 @@
 | 
				
			|||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mgcp_ratectr.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RTP_PORT_DEFAULT_RANGE_START 16002
 | 
					#define RTP_PORT_DEFAULT_RANGE_START 16002
 | 
				
			||||||
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
 | 
					#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,7 +45,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
struct mgcp_config;
 | 
					struct mgcp_config;
 | 
				
			||||||
struct mgcp_trunk_config;
 | 
					struct mgcp_trunk;
 | 
				
			||||||
struct mgcp_rtp_end;
 | 
					struct mgcp_rtp_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_ENDP_CRCX 1
 | 
					#define MGCP_ENDP_CRCX 1
 | 
				
			||||||
@@ -59,10 +62,9 @@ struct mgcp_rtp_end;
 | 
				
			|||||||
#define MGCP_POLICY_REJECT	5
 | 
					#define MGCP_POLICY_REJECT	5
 | 
				
			||||||
#define MGCP_POLICY_DEFER	6
 | 
					#define MGCP_POLICY_DEFER	6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int (*mgcp_realloc)(struct mgcp_trunk_config *cfg, int endpoint);
 | 
					typedef int (*mgcp_change)(struct mgcp_endpoint *endp, int state);
 | 
				
			||||||
typedef int (*mgcp_change)(struct mgcp_trunk_config *cfg, int endpoint, int state);
 | 
					typedef int (*mgcp_policy)(struct mgcp_endpoint *endp, int state, const char *transaction_id);
 | 
				
			||||||
typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int state, const char *transactio_id);
 | 
					typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
 | 
				
			||||||
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
 | 
					 | 
				
			||||||
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 | 
					typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -93,7 +95,8 @@ typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
struct mgcp_port_range {
 | 
					struct mgcp_port_range {
 | 
				
			||||||
	/* addr or NULL to fall-back to default */
 | 
						/* addr or NULL to fall-back to default */
 | 
				
			||||||
	char *bind_addr;
 | 
						char *bind_addr_v4;
 | 
				
			||||||
 | 
						char *bind_addr_v6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dynamically allocated */
 | 
						/* dynamically allocated */
 | 
				
			||||||
	int range_start;
 | 
						int range_start;
 | 
				
			||||||
@@ -119,116 +122,6 @@ struct mgcp_port_range {
 | 
				
			|||||||
#define MGCP_KEEPALIVE_ONCE (-1)
 | 
					#define MGCP_KEEPALIVE_ONCE (-1)
 | 
				
			||||||
#define MGCP_KEEPALIVE_NEVER 0
 | 
					#define MGCP_KEEPALIVE_NEVER 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Global MCGP general rate counters */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_MSGS_TOTAL,
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_MSGS_RETRANSMITTED,
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_MSGS_HANDLED,
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_MSGS_UNHANDLED,
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_FAIL_MSG_PARSE,
 | 
					 | 
				
			||||||
	MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global MCGP CRCX related rate counters */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	MGCP_CRCX_SUCCESS,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_BAD_ACTION,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_UNHANDLED_PARAM,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_MISSING_CALLID,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_INVALID_MODE,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_LIMIT_EXCEEDED,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_UNKNOWN_CALLID,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_ALLOC_CONN,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_START_RTP,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_NO_OSMUX,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
 | 
					 | 
				
			||||||
	MGCP_CRCX_FAIL_BIND_PORT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global MCGP MDCX related rate counters */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	MGCP_MDCX_SUCCESS,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_WILDCARD,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_NO_CONN,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_INVALID_CALLID,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_INVALID_CONNID,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_UNHANDLED_PARAM,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_NO_CONNID,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_CONN_NOT_FOUND,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_INVALID_MODE,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_START_RTP,
 | 
					 | 
				
			||||||
	MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_MDCX_DEFERRED_BY_POLICY
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global MCGP DLCX related rate counters */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	MGCP_DLCX_SUCCESS,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_WILDCARD,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_NO_CONN,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_INVALID_CALLID,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_INVALID_CONNID,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 | 
					 | 
				
			||||||
	MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
 | 
					 | 
				
			||||||
	MGCP_DLCX_DEFERRED_BY_POLICY,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_trunk_config {
 | 
					 | 
				
			||||||
	struct llist_head entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int trunk_nr;
 | 
					 | 
				
			||||||
	int trunk_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *audio_fmtp_extra;
 | 
					 | 
				
			||||||
	char *audio_name;
 | 
					 | 
				
			||||||
	int audio_payload;
 | 
					 | 
				
			||||||
	int audio_send_ptime;
 | 
					 | 
				
			||||||
	int audio_send_name;
 | 
					 | 
				
			||||||
	int audio_loop;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int no_audio_transcoding;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int omit_rtcp;
 | 
					 | 
				
			||||||
	int keepalive_interval;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* RTP patching */
 | 
					 | 
				
			||||||
	int force_constant_ssrc; /* 0: don't, 1: once */
 | 
					 | 
				
			||||||
	int force_aligned_timing;
 | 
					 | 
				
			||||||
	bool rfc5993_hr_convert;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* spec handling */
 | 
					 | 
				
			||||||
	int force_realloc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* timer */
 | 
					 | 
				
			||||||
	struct osmo_timer_list keepalive_timer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* When set, incoming RTP packets are not filtered
 | 
					 | 
				
			||||||
	 * when ports and ip-address do not match (debug) */
 | 
					 | 
				
			||||||
	int rtp_accept_all;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unsigned int number_endpoints;
 | 
					 | 
				
			||||||
	int vty_number_endpoints;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endpoints;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Rate counter group which contains stats for generic MGCP events. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *mgcp_general_ctr_group;
 | 
					 | 
				
			||||||
	/* Rate counter group which contains stats for processed CRCX commands. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *mgcp_crcx_ctr_group;
 | 
					 | 
				
			||||||
	/* Rate counter group which contains stats for processed MDCX commands. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *mgcp_mdcx_ctr_group;
 | 
					 | 
				
			||||||
	/* Rate counter group which contains stats for processed DLCX commands. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
					 | 
				
			||||||
	/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *all_rtp_conn_stats;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum mgcp_role {
 | 
					enum mgcp_role {
 | 
				
			||||||
	MGCP_BSC = 0,
 | 
						MGCP_BSC = 0,
 | 
				
			||||||
	MGCP_BSC_NAT,
 | 
						MGCP_BSC_NAT,
 | 
				
			||||||
@@ -256,14 +149,12 @@ struct mgcp_config {
 | 
				
			|||||||
	mgcp_change change_cb;
 | 
						mgcp_change change_cb;
 | 
				
			||||||
	mgcp_policy policy_cb;
 | 
						mgcp_policy policy_cb;
 | 
				
			||||||
	mgcp_reset reset_cb;
 | 
						mgcp_reset reset_cb;
 | 
				
			||||||
	mgcp_realloc realloc_cb;
 | 
					 | 
				
			||||||
	mgcp_rqnt rqnt_cb;
 | 
						mgcp_rqnt rqnt_cb;
 | 
				
			||||||
	void *data;
 | 
						void *data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t last_call_id;
 | 
						uint32_t last_call_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* trunk handling */
 | 
						/* list holding the trunks */
 | 
				
			||||||
	struct mgcp_trunk_config trunk;
 | 
					 | 
				
			||||||
	struct llist_head trunks;
 | 
						struct llist_head trunks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum mgcp_role role;
 | 
						enum mgcp_role role;
 | 
				
			||||||
@@ -294,6 +185,10 @@ struct mgcp_config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* osmocom CTRL interface */
 | 
						/* osmocom CTRL interface */
 | 
				
			||||||
	struct ctrl_handle *ctrl;
 | 
						struct ctrl_handle *ctrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* global rate counters to measure the MGWs overall performance and
 | 
				
			||||||
 | 
						 * health */
 | 
				
			||||||
 | 
						struct mgcp_ratectr_global ratectr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* config management */
 | 
					/* config management */
 | 
				
			||||||
@@ -301,8 +196,7 @@ struct mgcp_config *mgcp_config_alloc(void);
 | 
				
			|||||||
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
					int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			||||||
		      enum mgcp_role role);
 | 
							      enum mgcp_role role);
 | 
				
			||||||
int mgcp_vty_init(void);
 | 
					int mgcp_vty_init(void);
 | 
				
			||||||
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
 | 
					void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval);
 | 
				
			||||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * format helper functions
 | 
					 * format helper functions
 | 
				
			||||||
@@ -310,9 +204,9 @@ void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
 | 
				
			|||||||
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
 | 
					struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
 | 
					int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
 | 
				
			||||||
int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
					int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
 | 
					int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
 | 
				
			||||||
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
 | 
					int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, char *buf, int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,19 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_DEFAULT_RATE  8000
 | 
				
			||||||
 | 
					#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PTYPE_UNDEFINED (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
					void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void mgcp_codec_reset_all(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_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);
 | 
					int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
				
			||||||
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,6 +100,10 @@ static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
				
			|||||||
/* A prefix to denote the virtual trunk (RTP on both ends) */
 | 
					/* A prefix to denote the virtual trunk (RTP on both ends) */
 | 
				
			||||||
#define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"
 | 
					#define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A prefix to denote the e1 trunk
 | 
				
			||||||
 | 
					 * (see also RFC3435 section E.2) */
 | 
				
			||||||
 | 
					#define MGCP_ENDPOINT_PREFIX_E1_TRUNK "ds/e1-"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Maximal number of payload types / codecs that can be negotiated via SDP at
 | 
					/* Maximal number of payload types / codecs that can be negotiated via SDP at
 | 
				
			||||||
 * at once. */
 | 
					 * at once. */
 | 
				
			||||||
#define MGCP_MAX_CODECS 10
 | 
					#define MGCP_MAX_CODECS 10
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,11 +23,114 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
#include <osmocom/core/linuxlist.h>
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
				
			||||||
 | 
					         (conn)->id, \
 | 
				
			||||||
 | 
					         ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CONN(conn, level, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DRTP, level, "(%s I:%s) " fmt, \
 | 
				
			||||||
 | 
						     (conn)->endp ? (conn)->endp->name : "none", (conn)->id, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
 | 
				
			||||||
 | 
						LOG_CONN((conn_rtp)->conn, level, fmt, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
				
			||||||
 | 
					enum mgcp_conn_rtp_type {
 | 
				
			||||||
 | 
						MGCP_RTP_DEFAULT	= 0,
 | 
				
			||||||
 | 
						MGCP_OSMUX_BSC,
 | 
				
			||||||
 | 
						MGCP_OSMUX_BSC_NAT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
 | 
					 *  contains a useful connection description (currently only RTP) */
 | 
				
			||||||
 | 
					enum mgcp_conn_type {
 | 
				
			||||||
 | 
						MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MGCP connection (RTP) */
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Backpointer to conn struct */
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Specific connection type */
 | 
				
			||||||
 | 
						enum mgcp_conn_rtp_type type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Port status */
 | 
				
			||||||
 | 
						struct mgcp_rtp_end end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Sequence bits */
 | 
				
			||||||
 | 
						struct mgcp_rtp_state state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* taps for the rtp connection; one per direction */
 | 
				
			||||||
 | 
						struct mgcp_rtp_tap tap_in;
 | 
				
			||||||
 | 
						struct mgcp_rtp_tap tap_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Osmux states (optional) */
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							/* Osmux state: disabled, activating, active */
 | 
				
			||||||
 | 
							enum osmux_state state;
 | 
				
			||||||
 | 
							/* Is cid holding valid data? is it allocated from pool? */
 | 
				
			||||||
 | 
							bool cid_allocated;
 | 
				
			||||||
 | 
							/* Allocated Osmux circuit ID for this conn */
 | 
				
			||||||
 | 
							uint8_t cid;
 | 
				
			||||||
 | 
							/* handle to batch messages */
 | 
				
			||||||
 | 
							struct osmux_in_handle *in;
 | 
				
			||||||
 | 
							/* handle to unbatch messages */
 | 
				
			||||||
 | 
							struct osmux_out_handle out;
 | 
				
			||||||
 | 
							/* statistics */
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								uint32_t chunks;
 | 
				
			||||||
 | 
								uint32_t octets;
 | 
				
			||||||
 | 
							} stats;
 | 
				
			||||||
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct rate_ctr_group *rate_ctr_group;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! MGCP connection (untyped) */
 | 
				
			||||||
 | 
					struct mgcp_conn {
 | 
				
			||||||
 | 
						/*! list head */
 | 
				
			||||||
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! Backpointer to the endpoint where the conn belongs to */
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! type of the connection (union) */
 | 
				
			||||||
 | 
						enum mgcp_conn_type type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! mode of the connection */
 | 
				
			||||||
 | 
						enum mgcp_connection_mode mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! copy of the mode to restore the original setting (VTY) */
 | 
				
			||||||
 | 
						enum mgcp_connection_mode mode_orig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! connection id to identify the connection */
 | 
				
			||||||
 | 
						char id[MGCP_CONN_ID_MAXLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! human readable name (vty, logging) */
 | 
				
			||||||
 | 
						char name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! activity tracker (for cleaning up inactive connections) */
 | 
				
			||||||
 | 
						struct osmo_timer_list watchdog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! union with connection description */
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct mgcp_conn_rtp rtp;
 | 
				
			||||||
 | 
						} u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! pointer to optional private data */
 | 
				
			||||||
 | 
						void *priv;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RTP connection related counters */
 | 
					/* RTP connection related counters */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	IN_STREAM_ERR_TSTMP_CTR,
 | 
						IN_STREAM_ERR_TSTMP_CTR,
 | 
				
			||||||
@@ -68,6 +171,11 @@ static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
						[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
 | 
					static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
				
			||||||
 | 
						return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
					struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			||||||
				  enum mgcp_conn_type type, char *name);
 | 
									  enum mgcp_conn_type type, char *name);
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
 | 
					struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
 | 
				
			||||||
@@ -78,3 +186,5 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
 | 
				
			|||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
 | 
					void mgcp_conn_free_all(struct mgcp_endpoint *endp);
 | 
				
			||||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
					char *mgcp_conn_dump(struct mgcp_conn *conn);
 | 
				
			||||||
struct mgcp_conn *mgcp_find_dst_conn(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);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								include/osmocom/mgcp/mgcp_e1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								include/osmocom/mgcp/mgcp_e1.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A 64k timeslot on an E1 line can be subdevied into the following
 | 
				
			||||||
 | 
					 * subslot combinations:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * subslot:                                          offset:
 | 
				
			||||||
 | 
					 * [          ][          ][   16k    ][8k_subslot]  0
 | 
				
			||||||
 | 
					 * [          ][   32k    ][_subslot__][8k_subslot]  1
 | 
				
			||||||
 | 
					 * [          ][ subslot  ][   16k    ][8k_subslot]  2
 | 
				
			||||||
 | 
					 * [   64k    ][__________][_subslot__][8k_subslot]  3
 | 
				
			||||||
 | 
					 * [ timeslot ][          ][   16k    ][8k_subslot]  4
 | 
				
			||||||
 | 
					 * [          ][   32K    ][_subslot__][8k_subslot]  5
 | 
				
			||||||
 | 
					 * [          ][ subslot  ][   16k    ][8k_subslot]  6
 | 
				
			||||||
 | 
					 * [          ][          ][ subslot  ][8k_subslot]  7
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Since overlapping assignment of subslots is not possible there is a limited
 | 
				
			||||||
 | 
					 * set of subslot assignments possible. The e1_rates array lists the possible
 | 
				
			||||||
 | 
					 * assignments as depicted above. Also each subslot assignment comes along with
 | 
				
			||||||
 | 
					 * a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit
 | 
				
			||||||
 | 
					 * offsets. */
 | 
				
			||||||
 | 
					static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
 | 
				
			||||||
 | 
					static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
 | 
				
			||||||
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
 | 
				
			||||||
@@ -23,15 +23,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sockaddr_in;
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/i460_mux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sockaddr;
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callback type for RTP dispatcher functions
 | 
					/* Number of E1 subslots (different variants, not all useable at the same time) */
 | 
				
			||||||
   (e.g mgcp_dispatch_rtp_bridge_cb, see below) */
 | 
					#define MGCP_ENDP_E1_SUBSLOTS 15
 | 
				
			||||||
typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
 | 
					
 | 
				
			||||||
				     char *buf, unsigned int buf_size,
 | 
					#define LOGPENDP(endp, cat, level, fmt, args...) \
 | 
				
			||||||
				     struct mgcp_conn *conn);
 | 
					LOGP(cat, level, "endpoint:%s " fmt, \
 | 
				
			||||||
 | 
					     endp ? endp->name : "none", \
 | 
				
			||||||
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_rtp_msg_ctx {
 | 
				
			||||||
 | 
						int proto;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
 | 
						struct osmo_sockaddr *from_addr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OSMO_RTP_MSG_CTX(MSGB) ((struct osmo_rtp_msg_ctx*)(MSGB)->cb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo_static_assert(sizeof(((struct msgb*)0)->cb) >= sizeof(struct osmo_rtp_msg_ctx), osmo_rtp_msg_ctx_fits_in_msgb_cb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).
 | 
				
			||||||
 | 
					 * The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */
 | 
				
			||||||
 | 
					typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callback type for endpoint specific cleanup actions. This function
 | 
					/* Callback type for endpoint specific cleanup actions. This function
 | 
				
			||||||
 * is automatically executed when a connection is freed (see mgcp_conn_free()
 | 
					 * is automatically executed when a connection is freed (see mgcp_conn_free()
 | 
				
			||||||
@@ -55,6 +75,7 @@ struct mgcp_endpoint_type {
 | 
				
			|||||||
/*! MGCP endpoint typeset */
 | 
					/*! MGCP endpoint typeset */
 | 
				
			||||||
struct mgcp_endpoint_typeset {
 | 
					struct mgcp_endpoint_typeset {
 | 
				
			||||||
	struct mgcp_endpoint_type rtp;
 | 
						struct mgcp_endpoint_type rtp;
 | 
				
			||||||
 | 
						struct mgcp_endpoint_type e1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! static MGCP endpoint typeset (pre-initalized, read-only) */
 | 
					/*! static MGCP endpoint typeset (pre-initalized, read-only) */
 | 
				
			||||||
@@ -63,6 +84,9 @@ extern const struct mgcp_endpoint_typeset ep_typeset;
 | 
				
			|||||||
/*! MGCP endpoint model */
 | 
					/*! MGCP endpoint model */
 | 
				
			||||||
struct mgcp_endpoint {
 | 
					struct mgcp_endpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! Unique endpoint name, used for addressing via MGCP */
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! Call identifier string (as supplied by the call agant) */
 | 
						/*! Call identifier string (as supplied by the call agant) */
 | 
				
			||||||
	char *callid;
 | 
						char *callid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,8 +99,8 @@ struct mgcp_endpoint {
 | 
				
			|||||||
	/*! Backpointer to the MGW configuration */
 | 
						/*! Backpointer to the MGW configuration */
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! Backpointer to the Trunk specific configuration */
 | 
						/*! Backpointer to the trunk this endpoint belongs to */
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! Endpoint properties (see above) */
 | 
						/*! Endpoint properties (see above) */
 | 
				
			||||||
	const struct mgcp_endpoint_type *type;
 | 
						const struct mgcp_endpoint_type *type;
 | 
				
			||||||
@@ -93,9 +117,27 @@ struct mgcp_endpoint {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
						/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* E1 specific */
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct osmo_i460_schan_desc scd;
 | 
				
			||||||
 | 
							struct osmo_i460_subchan *schan;
 | 
				
			||||||
 | 
							struct osmo_fsm_inst *trau_sync_fi;
 | 
				
			||||||
 | 
							struct osmo_trau2rtp_state *trau_rtp_st;
 | 
				
			||||||
 | 
							uint8_t last_amr_ft;
 | 
				
			||||||
 | 
							struct mgcp_rtp_codec *last_codec;
 | 
				
			||||||
 | 
						} e1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Extract endpoint number for a given endpoint */
 | 
					struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
 | 
				
			||||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
 | 
				
			||||||
 | 
					void mgcp_endp_update(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			||||||
 | 
										      const struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			||||||
 | 
										struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					bool mgcp_endp_avail(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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,352 +0,0 @@
 | 
				
			|||||||
/* MGCP Private Data */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
					 | 
				
			||||||
 * (C) 2009-2012 by On-Waves
 | 
					 | 
				
			||||||
 * 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/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
#include <osmocom/core/select.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					 | 
				
			||||||
#include <osmocom/core/linuxlist.h>
 | 
					 | 
				
			||||||
#include <osmocom/core/counter.h>
 | 
					 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CI_UNUSED 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* FIXME: This this is only needed to compile the currently
 | 
					 | 
				
			||||||
 * broken OSMUX support. Remove when fixed */
 | 
					 | 
				
			||||||
#define CONN_ID_BTS "0"
 | 
					 | 
				
			||||||
#define CONN_ID_NET "1"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum mgcp_trunk_type {
 | 
					 | 
				
			||||||
	MGCP_TRUNK_VIRTUAL,
 | 
					 | 
				
			||||||
	MGCP_TRUNK_E1,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_rtp_stream_state {
 | 
					 | 
				
			||||||
	uint32_t ssrc;
 | 
					 | 
				
			||||||
	uint16_t last_seq;
 | 
					 | 
				
			||||||
	uint32_t last_timestamp;
 | 
					 | 
				
			||||||
	struct rate_ctr *err_ts_ctr;
 | 
					 | 
				
			||||||
	int32_t last_tsdelta;
 | 
					 | 
				
			||||||
	uint32_t last_arrival_time;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_rtp_state {
 | 
					 | 
				
			||||||
	/* has this state structure been initialized? */
 | 
					 | 
				
			||||||
	int initialized;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		/* are we patching the SSRC value? */
 | 
					 | 
				
			||||||
		int patch_ssrc;
 | 
					 | 
				
			||||||
		/* original SSRC (to which we shall patch any different SSRC) */
 | 
					 | 
				
			||||||
		uint32_t orig_ssrc;
 | 
					 | 
				
			||||||
		/* offset to apply on the sequence number */
 | 
					 | 
				
			||||||
		int seq_offset;
 | 
					 | 
				
			||||||
		/* offset to apply on the timestamp number */
 | 
					 | 
				
			||||||
		int32_t timestamp_offset;
 | 
					 | 
				
			||||||
	} patch;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* duration of a packet (FIXME: in which unit?) */
 | 
					 | 
				
			||||||
	uint32_t packet_duration;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct mgcp_rtp_stream_state in_stream;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_stream_state out_stream;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* jitter and packet loss calculation */
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		int initialized;
 | 
					 | 
				
			||||||
		uint16_t base_seq;
 | 
					 | 
				
			||||||
		uint16_t max_seq;
 | 
					 | 
				
			||||||
		uint32_t ssrc;
 | 
					 | 
				
			||||||
		uint32_t jitter;
 | 
					 | 
				
			||||||
		int32_t transit;
 | 
					 | 
				
			||||||
		int cycles;
 | 
					 | 
				
			||||||
	} stats;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
	char *subtype_name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool param_present;
 | 
					 | 
				
			||||||
	struct mgcp_codec_param param;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
					 | 
				
			||||||
struct mgcp_rtp_end {
 | 
					 | 
				
			||||||
	/* local IP address of the RTP socket */
 | 
					 | 
				
			||||||
	struct in_addr addr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* in network byte order */
 | 
					 | 
				
			||||||
	int rtp_port, 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 */
 | 
					 | 
				
			||||||
	char *fmtp_extra;
 | 
					 | 
				
			||||||
	/* are we transmitting packets (1) or dropping (0) outbound packets */
 | 
					 | 
				
			||||||
	int output_enabled;
 | 
					 | 
				
			||||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
					 | 
				
			||||||
	int force_output_ptime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* 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_fd rtp;
 | 
					 | 
				
			||||||
	struct osmo_fd rtcp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* local UDP port number of the RTP socket; RTCP is +1 */
 | 
					 | 
				
			||||||
	int local_port;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_rtp_tap {
 | 
					 | 
				
			||||||
	/* is this tap active (1) or not (0) */
 | 
					 | 
				
			||||||
	int enabled;
 | 
					 | 
				
			||||||
	/* IP/port to which we're forwarding the tapped data */
 | 
					 | 
				
			||||||
	struct sockaddr_in forward;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_lco {
 | 
					 | 
				
			||||||
	char *string;
 | 
					 | 
				
			||||||
	char *codec;
 | 
					 | 
				
			||||||
	int pkt_period_min; /* time in ms */
 | 
					 | 
				
			||||||
	int pkt_period_max; /* time in ms */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
					 | 
				
			||||||
enum mgcp_conn_rtp_type {
 | 
					 | 
				
			||||||
	MGCP_RTP_DEFAULT	= 0,
 | 
					 | 
				
			||||||
	MGCP_OSMUX_BSC,
 | 
					 | 
				
			||||||
	MGCP_OSMUX_BSC_NAT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					 | 
				
			||||||
struct mgcp_conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* MGCP connection (RTP) */
 | 
					 | 
				
			||||||
struct mgcp_conn_rtp {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Backpointer to conn struct */
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Specific connection type */
 | 
					 | 
				
			||||||
	enum mgcp_conn_rtp_type type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Port status */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Sequence bits */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_state state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* taps for the rtp connection; one per direction */
 | 
					 | 
				
			||||||
	struct mgcp_rtp_tap tap_in;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_tap tap_out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Osmux states (optional) */
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		/* Osmux state: disabled, activating, active */
 | 
					 | 
				
			||||||
		enum osmux_state state;
 | 
					 | 
				
			||||||
		/* Is cid holding valid data? is it allocated from pool? */
 | 
					 | 
				
			||||||
		bool cid_allocated;
 | 
					 | 
				
			||||||
		/* Allocated Osmux circuit ID for this conn */
 | 
					 | 
				
			||||||
		uint8_t cid;
 | 
					 | 
				
			||||||
		/* handle to batch messages */
 | 
					 | 
				
			||||||
		struct osmux_in_handle *in;
 | 
					 | 
				
			||||||
		/* handle to unbatch messages */
 | 
					 | 
				
			||||||
		struct osmux_out_handle out;
 | 
					 | 
				
			||||||
		/* statistics */
 | 
					 | 
				
			||||||
		struct {
 | 
					 | 
				
			||||||
			uint32_t chunks;
 | 
					 | 
				
			||||||
			uint32_t octets;
 | 
					 | 
				
			||||||
		} stats;
 | 
					 | 
				
			||||||
	} osmux;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct rate_ctr_group *rate_ctr_group;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					 | 
				
			||||||
 *  contains a useful connection description (currently only RTP) */
 | 
					 | 
				
			||||||
enum mgcp_conn_type {
 | 
					 | 
				
			||||||
	MGCP_CONN_TYPE_RTP,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! MGCP connection (untyped) */
 | 
					 | 
				
			||||||
struct mgcp_conn {
 | 
					 | 
				
			||||||
	/*! list head */
 | 
					 | 
				
			||||||
	struct llist_head entry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! Backpointer to the endpoint where the conn belongs to */
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! type of the connection (union) */
 | 
					 | 
				
			||||||
	enum mgcp_conn_type type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! mode of the connection */
 | 
					 | 
				
			||||||
	enum mgcp_connection_mode mode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! copy of the mode to restore the original setting (VTY) */
 | 
					 | 
				
			||||||
	enum mgcp_connection_mode mode_orig;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! connection id to identify the connection */
 | 
					 | 
				
			||||||
	char id[MGCP_CONN_ID_MAXLEN];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! human readable name (vty, logging) */
 | 
					 | 
				
			||||||
	char name[256];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! activity tracker (for cleaning up inactive connections) */
 | 
					 | 
				
			||||||
	struct osmo_timer_list watchdog;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! union with connection description */
 | 
					 | 
				
			||||||
	union {
 | 
					 | 
				
			||||||
		struct mgcp_conn_rtp rtp;
 | 
					 | 
				
			||||||
	} u;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*! pointer to optional private data */
 | 
					 | 
				
			||||||
	void *priv;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_endpoint_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Internal structure while parsing a request
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct mgcp_parse_data {
 | 
					 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	char *trans;
 | 
					 | 
				
			||||||
	char *save;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
 | 
					 | 
				
			||||||
	      char *buf, int rc, struct mgcp_conn_rtp *conn_src,
 | 
					 | 
				
			||||||
	      struct mgcp_conn_rtp *conn_dst);
 | 
					 | 
				
			||||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
 | 
					 | 
				
			||||||
				unsigned int buf_size, struct mgcp_conn *conn);
 | 
					 | 
				
			||||||
void mgcp_cleanup_rtp_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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* For transcoding we need to manage an in and an output that are connected */
 | 
					 | 
				
			||||||
static inline int endp_back_channel(int endpoint)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return endpoint + 60;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index);
 | 
					 | 
				
			||||||
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
char *get_lco_identifier(const char *options);
 | 
					 | 
				
			||||||
int check_local_cx_options(void *ctx, const char *options);
 | 
					 | 
				
			||||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
					 | 
				
			||||||
			 struct mgcp_rtp_end *rtp);
 | 
					 | 
				
			||||||
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
				  struct mgcp_rtp_end *rtp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* payload processing default functions */
 | 
					 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
					 | 
				
			||||||
				char *data, int *len, int buf_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
				      struct mgcp_conn_rtp *conn_dst,
 | 
					 | 
				
			||||||
				      struct mgcp_conn_rtp *conn_src);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
					  const struct mgcp_rtp_codec **codec,
 | 
					 | 
				
			||||||
					  const char **fmtp_extra,
 | 
					 | 
				
			||||||
					  struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* internal RTP Annex A counting */
 | 
					 | 
				
			||||||
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
					 | 
				
			||||||
			const uint16_t seq, const int32_t transit,
 | 
					 | 
				
			||||||
			const uint32_t ssrc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_set_ip_tos(int fd, int tos);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					 | 
				
			||||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
					 | 
				
			||||||
	return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	MGCP_DEST_NET = 0,
 | 
					 | 
				
			||||||
	MGCP_DEST_BTS,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * SDP related information
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
/* Assume audio frame length of 20ms */
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE  8000
 | 
					 | 
				
			||||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PTYPE_UNDEFINED (-1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LOGPENDP(endp, cat, level, fmt, args...) \
 | 
					 | 
				
			||||||
LOGP(cat, level, "endpoint:0x%x " fmt, \
 | 
					 | 
				
			||||||
     endp ? ENDPOINT_NUMBER(endp) : -1, \
 | 
					 | 
				
			||||||
     ## args)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
					 | 
				
			||||||
LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
					 | 
				
			||||||
         (conn)->id, \
 | 
					 | 
				
			||||||
         ## args)
 | 
					 | 
				
			||||||
							
								
								
									
										169
									
								
								include/osmocom/mgcp/mgcp_network.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								include/osmocom/mgcp/mgcp_network.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MGCP_DUMMY_LOAD 0x23
 | 
				
			||||||
 | 
					#define RTP_BUF_SIZE	4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_stream_state {
 | 
				
			||||||
 | 
						uint32_t ssrc;
 | 
				
			||||||
 | 
						uint16_t last_seq;
 | 
				
			||||||
 | 
						uint32_t last_timestamp;
 | 
				
			||||||
 | 
						struct rate_ctr *err_ts_ctr;
 | 
				
			||||||
 | 
						int32_t last_tsdelta;
 | 
				
			||||||
 | 
						uint32_t last_arrival_time;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_state {
 | 
				
			||||||
 | 
						/* has this state structure been initialized? */
 | 
				
			||||||
 | 
						int initialized;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							/* are we patching the SSRC value? */
 | 
				
			||||||
 | 
							int patch_ssrc;
 | 
				
			||||||
 | 
							/* original SSRC (to which we shall patch any different SSRC) */
 | 
				
			||||||
 | 
							uint32_t orig_ssrc;
 | 
				
			||||||
 | 
							/* offset to apply on the sequence number */
 | 
				
			||||||
 | 
							int seq_offset;
 | 
				
			||||||
 | 
							/* offset to apply on the timestamp number */
 | 
				
			||||||
 | 
							int32_t timestamp_offset;
 | 
				
			||||||
 | 
						} patch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* duration of a packet (FIXME: in which unit?) */
 | 
				
			||||||
 | 
						uint32_t packet_duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note: These states are not continuously updated, they serve as an
 | 
				
			||||||
 | 
						 * information source to patch certain values in the RTP header. Do
 | 
				
			||||||
 | 
						 * not use this state if constantly updated data about the RTP stream
 | 
				
			||||||
 | 
						 * is needed. (see also mgcp_patch_and_count() */
 | 
				
			||||||
 | 
						struct mgcp_rtp_stream_state in_stream;
 | 
				
			||||||
 | 
						struct mgcp_rtp_stream_state out_stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* jitter and packet loss calculation */
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							int initialized;
 | 
				
			||||||
 | 
							uint16_t base_seq;
 | 
				
			||||||
 | 
							uint16_t max_seq;
 | 
				
			||||||
 | 
							uint32_t ssrc;
 | 
				
			||||||
 | 
							uint32_t jitter;
 | 
				
			||||||
 | 
							int32_t transit;
 | 
				
			||||||
 | 
							int cycles;
 | 
				
			||||||
 | 
						} stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Alternative values for RTP tx, in case no sufficient header
 | 
				
			||||||
 | 
						 * information is available so the header needs to be generated
 | 
				
			||||||
 | 
						 * locally (when just forwarding packets, the header of incoming
 | 
				
			||||||
 | 
						 * data is just re-used) */
 | 
				
			||||||
 | 
						uint16_t alt_rtp_tx_sequence;
 | 
				
			||||||
 | 
						uint32_t alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
						char *subtype_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 rtp_port, 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 */
 | 
				
			||||||
 | 
						char *fmtp_extra;
 | 
				
			||||||
 | 
						/* are we transmitting packets (1) or dropping (0) outbound packets */
 | 
				
			||||||
 | 
						int output_enabled;
 | 
				
			||||||
 | 
						/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
				
			||||||
 | 
						int force_output_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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_fd rtp;
 | 
				
			||||||
 | 
						struct osmo_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];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_tap {
 | 
				
			||||||
 | 
						/* is this tap active (1) or not (0) */
 | 
				
			||||||
 | 
						int enabled;
 | 
				
			||||||
 | 
						/* IP/port to which we're forwarding the tapped data */
 | 
				
			||||||
 | 
						struct osmo_sockaddr forward;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
 | 
				
			||||||
 | 
						      struct msgb *msg, struct mgcp_conn_rtp *conn_src,
 | 
				
			||||||
 | 
						      struct mgcp_conn_rtp *conn_dst);
 | 
				
			||||||
 | 
					int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
 | 
								  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
				
			||||||
 | 
					void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					int mgcp_set_ip_tos(int fd, int tos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* payload processing default functions */
 | 
				
			||||||
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
				
			||||||
 | 
									char *data, int *len, int buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									      struct mgcp_conn_rtp *conn_dst,
 | 
				
			||||||
 | 
									      struct mgcp_conn_rtp *conn_src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										  const struct mgcp_rtp_codec **codec,
 | 
				
			||||||
 | 
										  const char **fmtp_extra,
 | 
				
			||||||
 | 
										  struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* internal RTP Annex A counting */
 | 
				
			||||||
 | 
					void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
				
			||||||
 | 
								const uint16_t seq, const int32_t transit,
 | 
				
			||||||
 | 
								const uint32_t ssrc);
 | 
				
			||||||
							
								
								
									
										27
									
								
								include/osmocom/mgcp/mgcp_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								include/osmocom/mgcp/mgcp_protocol.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Internal structure while parsing a request */
 | 
				
			||||||
 | 
					struct mgcp_parse_data {
 | 
				
			||||||
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						char *trans;
 | 
				
			||||||
 | 
						char *save;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Local connection options */
 | 
				
			||||||
 | 
					struct mgcp_lco {
 | 
				
			||||||
 | 
						char *string;
 | 
				
			||||||
 | 
						char *codec;
 | 
				
			||||||
 | 
						int pkt_period_min; /* time in ms */
 | 
				
			||||||
 | 
						int pkt_period_max; /* time in ms */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *get_lco_identifier(const char *options);
 | 
				
			||||||
 | 
					int check_local_cx_options(void *ctx, const char *options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_end;
 | 
				
			||||||
 | 
					void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			||||||
 | 
								 struct mgcp_rtp_end *rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									  struct mgcp_rtp_end *rtp);
 | 
				
			||||||
							
								
								
									
										95
									
								
								include/osmocom/mgcp/mgcp_ratectr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								include/osmocom/mgcp/mgcp_ratectr.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Global MCGP general rate counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_MSGS_TOTAL,
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_MSGS_RETRANSMITTED,
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_MSGS_HANDLED,
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_MSGS_UNHANDLED,
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_FAIL_MSG_PARSE,
 | 
				
			||||||
 | 
						MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trunk-global MCGP CRCX related rate counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						MGCP_CRCX_SUCCESS,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_BAD_ACTION,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_UNHANDLED_PARAM,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_MISSING_CALLID,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_INVALID_MODE,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_LIMIT_EXCEEDED,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_UNKNOWN_CALLID,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_ALLOC_CONN,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_START_RTP,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_REJECTED_BY_POLICY,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_NO_OSMUX,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_BIND_PORT,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_AVAIL,
 | 
				
			||||||
 | 
						MGCP_CRCX_FAIL_CLAIM,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trunk-global MCGP MDCX related rate counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						MGCP_MDCX_SUCCESS,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_WILDCARD,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_NO_CONN,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_INVALID_CALLID,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_INVALID_CONNID,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_UNHANDLED_PARAM,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_NO_CONNID,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_CONN_NOT_FOUND,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_INVALID_MODE,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_START_RTP,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
 | 
				
			||||||
 | 
						MGCP_MDCX_DEFERRED_BY_POLICY,
 | 
				
			||||||
 | 
						MGCP_MDCX_FAIL_AVAIL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trunk-global MCGP DLCX related rate counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						MGCP_DLCX_SUCCESS,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_WILDCARD,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_NO_CONN,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_INVALID_CALLID,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_INVALID_CONNID,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
 | 
				
			||||||
 | 
						MGCP_DLCX_DEFERRED_BY_POLICY,
 | 
				
			||||||
 | 
						MGCP_DLCX_FAIL_AVAIL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trunk-global E1 related counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					        E1_I460_TRAU_RX_FAIL_CTR,
 | 
				
			||||||
 | 
					        E1_I460_TRAU_TX_FAIL_CTR,
 | 
				
			||||||
 | 
					        E1_I460_TRAU_MUX_EMPTY_CTR,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_ratectr_global {
 | 
				
			||||||
 | 
						/* Rate counter group which contains stats for generic MGCP events. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *mgcp_general_ctr_group;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_ratectr_trunk {
 | 
				
			||||||
 | 
						/* Rate counter group which contains stats for processed CRCX commands. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *mgcp_crcx_ctr_group;
 | 
				
			||||||
 | 
						/* Rate counter group which contains stats for processed MDCX commands. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *mgcp_mdcx_ctr_group;
 | 
				
			||||||
 | 
						/* Rate counter group which contains stats for processed DLCX commands. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
				
			||||||
 | 
						/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *all_rtp_conn_stats;
 | 
				
			||||||
 | 
						/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
				
			||||||
 | 
						struct rate_ctr_group *e1_stats;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr);
 | 
				
			||||||
 | 
					int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr);
 | 
				
			||||||
@@ -24,7 +24,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_format_stats(char *str, size_t str_len,  struct mgcp_conn *conn);
 | 
					void mgcp_format_stats(char *str, size_t str_len,  struct mgcp_conn *conn);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										78
									
								
								include/osmocom/mgcp/mgcp_trunk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								include/osmocom/mgcp/mgcp_trunk.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/gsm/i460_mux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGP(cat, level, "trunk:%u " fmt, \
 | 
				
			||||||
 | 
					     trunk ? trunk->trunk_nr : 0, \
 | 
				
			||||||
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum mgcp_trunk_type {
 | 
				
			||||||
 | 
						MGCP_TRUNK_VIRTUAL,
 | 
				
			||||||
 | 
						MGCP_TRUNK_E1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_trunk {
 | 
				
			||||||
 | 
						struct llist_head entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int trunk_nr;
 | 
				
			||||||
 | 
						enum mgcp_trunk_type trunk_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *audio_fmtp_extra;
 | 
				
			||||||
 | 
						int audio_send_ptime;
 | 
				
			||||||
 | 
						int audio_send_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int no_audio_transcoding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int omit_rtcp;
 | 
				
			||||||
 | 
						int keepalive_interval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* RTP patching */
 | 
				
			||||||
 | 
						int force_constant_ssrc; /* 0: don't, 1: once */
 | 
				
			||||||
 | 
						int force_aligned_timing;
 | 
				
			||||||
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* spec handling */
 | 
				
			||||||
 | 
						int force_realloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* timer */
 | 
				
			||||||
 | 
						struct osmo_timer_list keepalive_timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When set, incoming RTP packets are not filtered
 | 
				
			||||||
 | 
						 * when ports and ip-address do not match (debug) */
 | 
				
			||||||
 | 
						int rtp_accept_all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned int number_endpoints;
 | 
				
			||||||
 | 
						struct mgcp_endpoint **endpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* global rate counters to measure the trunks overall performance and health */
 | 
				
			||||||
 | 
						struct mgcp_ratectr_trunk ratectr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							/* Virtual trunk specific */
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								unsigned int vty_number_endpoints;
 | 
				
			||||||
 | 
							} v;
 | 
				
			||||||
 | 
							/* E1 specific */
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								unsigned int vty_line_nr;
 | 
				
			||||||
 | 
								bool ts_in_use[31];
 | 
				
			||||||
 | 
								struct osmo_i460_timeslot i460_ts[31];
 | 
				
			||||||
 | 
							} e1;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
 | 
				
			||||||
 | 
					int mgcp_trunk_equip(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr);
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
 | 
				
			||||||
 | 
					int e1_trunk_nr_from_epname(const char *epname);
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The virtual trunk is always created on trunk id 0 for historical reasons,
 | 
				
			||||||
 | 
					 * use this define constant as ID when allocating a virtual trunk. Other
 | 
				
			||||||
 | 
					 * trunks may be assigned with arbritrary id numbers */
 | 
				
			||||||
 | 
					#define MGCP_VIRT_TRUNK_ID 0
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
@@ -13,7 +14,7 @@ enum {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int osmux_init(int role, struct mgcp_config *cfg);
 | 
					int osmux_init(int role, struct mgcp_config *cfg);
 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
		      struct in_addr *addr, uint16_t port);
 | 
							      struct osmo_sockaddr *addr, uint16_t port);
 | 
				
			||||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
 | 
					int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
 | 
				
			||||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,3 +6,7 @@ enum mgcp_vty_node {
 | 
				
			|||||||
	MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
 | 
						MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
 | 
				
			||||||
	TRUNK_NODE,
 | 
						TRUNK_NODE,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum mgw_vty_cmd_attr {
 | 
				
			||||||
 | 
						MGW_CMD_ATTR_NEWCONN = 0,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp_client/mgcp_common.h>
 | 
					#include <osmocom/mgcp_client/mgcp_common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
					/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
 | 
					#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
 | 
					#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
					#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
					#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
				
			||||||
@@ -75,7 +75,7 @@ struct mgcp_response {
 | 
				
			|||||||
	char *body;
 | 
						char *body;
 | 
				
			||||||
	struct mgcp_response_head head;
 | 
						struct mgcp_response_head head;
 | 
				
			||||||
	uint16_t audio_port;
 | 
						uint16_t audio_port;
 | 
				
			||||||
	char audio_ip[INET_ADDRSTRLEN];
 | 
						char audio_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
	unsigned int ptime;
 | 
						unsigned int ptime;
 | 
				
			||||||
	enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
						enum mgcp_codecs codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int codecs_len;
 | 
						unsigned int codecs_len;
 | 
				
			||||||
@@ -133,10 +133,12 @@ int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
					const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
				
			||||||
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
 | 
					uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
 | 
				
			||||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp);
 | 
					uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp) OSMO_DEPRECATED("deprecated, returns 0");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp);
 | 
					const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp);
 | 
				
			||||||
const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
 | 
					const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
 | 
				
			||||||
 | 
					const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
				
			||||||
 | 
									  uint8_t rate, uint8_t offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Invoked when an MGCP response is received or sending failed.  When the
 | 
					/* Invoked when an MGCP response is received or sending failed.  When the
 | 
				
			||||||
 * response is passed as NULL, this indicates failure during transmission. */
 | 
					 * response is passed as NULL, this indicates failure during transmission. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,14 +8,14 @@
 | 
				
			|||||||
 *  (either remote or local). It is used to pass parameters (local) to the FSM
 | 
					 *  (either remote or local). It is used to pass parameters (local) to the FSM
 | 
				
			||||||
 *  and get responses (remote) from the FSM as pointer attached to the FSM
 | 
					 *  and get responses (remote) from the FSM as pointer attached to the FSM
 | 
				
			||||||
 *  event.
 | 
					 *  event.
 | 
				
			||||||
 * 
 | 
					 *
 | 
				
			||||||
 *  When modifiying a connection, the endpoint and call_id members may be left
 | 
					 *  When modifiying a connection, the endpoint and call_id members may be left
 | 
				
			||||||
 *  unpopulated. The call_id field is ignored in this case. If an endpoint
 | 
					 *  unpopulated. The call_id field is ignored in this case. If an endpoint
 | 
				
			||||||
 *  identifier is supplied it is checked against the internal state to make
 | 
					 *  identifier is supplied it is checked against the internal state to make
 | 
				
			||||||
 *  sure it is correct. */
 | 
					 *  sure it is correct. */
 | 
				
			||||||
struct mgcp_conn_peer {
 | 
					struct mgcp_conn_peer {
 | 
				
			||||||
	/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
 | 
						/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
 | 
				
			||||||
	char addr[INET_ADDRSTRLEN];
 | 
						char addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! RTP connection IP-Port (optional)  */
 | 
						/*! RTP connection IP-Port (optional)  */
 | 
				
			||||||
	uint16_t port;
 | 
						uint16_t port;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct mgcp_client {
 | 
					struct mgcp_client {
 | 
				
			||||||
	struct mgcp_client_conf actual;
 | 
						struct mgcp_client_conf actual;
 | 
				
			||||||
	uint32_t remote_addr;
 | 
					 | 
				
			||||||
	struct osmo_wqueue wq;
 | 
						struct osmo_wqueue wq;
 | 
				
			||||||
	mgcp_trans_id_t next_trans_id;
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
#include <osmocom/core/byteswap.h>
 | 
					#include <osmocom/core/byteswap.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
@@ -370,22 +371,37 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
 | 
				
			|||||||
/* Parse a line like "c=IN IP4 10.11.12.13" */
 | 
					/* Parse a line like "c=IN IP4 10.11.12.13" */
 | 
				
			||||||
static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
 | 
					static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct in_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
						bool is_ipv6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strlen(line) < 16)
 | 
						if (strncmp("c=IN IP", line, 7) != 0)
 | 
				
			||||||
		goto response_parse_failure;
 | 
							goto response_parse_failure;
 | 
				
			||||||
 | 
						line += 7;
 | 
				
			||||||
	/* The current implementation strictly supports IPV4 only ! */
 | 
						if (*line == '6')
 | 
				
			||||||
	if (memcmp("c=IN IP4 ", line, 9) != 0)
 | 
							is_ipv6 = true;
 | 
				
			||||||
 | 
						else if (*line == '4')
 | 
				
			||||||
 | 
							is_ipv6 = false;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		goto response_parse_failure;
 | 
							goto response_parse_failure;
 | 
				
			||||||
 | 
						line++;
 | 
				
			||||||
	/* Extract IP-Address */
 | 
						if (*line != ' ')
 | 
				
			||||||
	osmo_strlcpy(r->audio_ip, line + 9, sizeof(r->audio_ip));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check IP-Address */
 | 
					 | 
				
			||||||
	if (inet_aton(r->audio_ip, &ip_test) == 0)
 | 
					 | 
				
			||||||
		goto response_parse_failure;
 | 
							goto response_parse_failure;
 | 
				
			||||||
 | 
						line++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Extract and check IP-Address */
 | 
				
			||||||
 | 
						if (is_ipv6) {
 | 
				
			||||||
 | 
							/* 45 = INET6_ADDRSTRLEN -1 */
 | 
				
			||||||
 | 
							if (sscanf(line, "%45s", r->audio_ip) != 1)
 | 
				
			||||||
 | 
								goto response_parse_failure;
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET6, r->audio_ip, &ip_test) != 1)
 | 
				
			||||||
 | 
								goto response_parse_failure;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* 15 = INET_ADDRSTRLEN -1 */
 | 
				
			||||||
 | 
							if (sscanf(line, "%15s", r->audio_ip) != 1)
 | 
				
			||||||
 | 
								goto response_parse_failure;
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET, r->audio_ip, &ip_test) != 1)
 | 
				
			||||||
 | 
								goto response_parse_failure;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
response_parse_failure:
 | 
					response_parse_failure:
 | 
				
			||||||
@@ -735,6 +751,8 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	struct mgcp_client *mgcp;
 | 
						struct mgcp_client *mgcp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp = talloc_zero(ctx, struct mgcp_client);
 | 
						mgcp = talloc_zero(ctx, struct mgcp_client);
 | 
				
			||||||
 | 
						if (!mgcp)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&mgcp->responses_pending);
 | 
						INIT_LLIST_HEAD(&mgcp->responses_pending);
 | 
				
			||||||
	INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
 | 
						INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
 | 
				
			||||||
@@ -776,7 +794,7 @@ static int init_socket(struct mgcp_client *mgcp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* Initalize socket with the currently configured port
 | 
							/* Initalize socket with the currently configured port
 | 
				
			||||||
		 * number */
 | 
							 * number */
 | 
				
			||||||
		rc = osmo_sock_init2_ofd(&wq->bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
							rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
				
			||||||
					 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
										 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
				
			||||||
					 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
										 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
				
			||||||
		if (rc > 0)
 | 
							if (rc > 0)
 | 
				
			||||||
@@ -805,7 +823,6 @@ static int init_socket(struct mgcp_client *mgcp)
 | 
				
			|||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr_in addr;
 | 
					 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -815,6 +832,11 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wq = &mgcp->wq;
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
 | 
						osmo_wqueue_init(wq, 1024);
 | 
				
			||||||
 | 
						wq->read_cb = mgcp_do_read;
 | 
				
			||||||
 | 
						wq->write_cb = mgcp_do_write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = init_socket(mgcp);
 | 
						rc = init_socket(mgcp);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
@@ -825,14 +847,6 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
		goto error_close_fd;
 | 
							goto error_close_fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
 | 
					 | 
				
			||||||
	mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	osmo_wqueue_init(wq, 1024);
 | 
					 | 
				
			||||||
	wq->bfd.when = OSMO_FD_READ;
 | 
					 | 
				
			||||||
	wq->bfd.data = mgcp;
 | 
					 | 
				
			||||||
	wq->read_cb = mgcp_do_read;
 | 
					 | 
				
			||||||
	wq->write_cb = mgcp_do_write;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
						LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s\n", osmo_sock_get_name2(wq->bfd.fd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -859,12 +873,13 @@ uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp)
 | 
				
			|||||||
	return mgcp->actual.remote_port;
 | 
						return mgcp->actual.remote_port;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Get the IP-Aaddress of the associated MGW as its numeric representation.
 | 
					/*! Get the IP-Address of the associated MGW as its numeric representation.
 | 
				
			||||||
 | 
					 *  DEPRECATED, DON'T USE.
 | 
				
			||||||
 *  \param[in] mgcp MGCP client descriptor.
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns IP-Address as 32 bit integer (network byte order) */
 | 
					 *  \returns IP-Address as 32 bit integer (network byte order) */
 | 
				
			||||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
 | 
					uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return mgcp->remote_addr;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* To compose endpoint names, usually for CRCX, use this as domain name.
 | 
					/* To compose endpoint names, usually for CRCX, use this as domain name.
 | 
				
			||||||
@@ -892,11 +907,66 @@ static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgc
 | 
				
			|||||||
	return endpoint;
 | 
						return endpoint;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Compose endpoint name for a wildcarded request to the virtual trunk
 | 
				
			||||||
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \returns string containing the endpoint name (e.g. rtpbridge\*@mgw) */
 | 
				
			||||||
const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp)
 | 
					const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return _mgcp_client_name_append_domain(mgcp, "rtpbridge/*");
 | 
						return _mgcp_client_name_append_domain(mgcp, "rtpbridge/*");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Compose endpoint name for an E1 endpoint.
 | 
				
			||||||
 | 
					 *  \param[in] ctx talloc context.
 | 
				
			||||||
 | 
					 *  \param[in] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] trunk_id id number of the E1 trunk (1-64).
 | 
				
			||||||
 | 
					 *  \param[in] ts timeslot on the E1 trunk (1-31).
 | 
				
			||||||
 | 
					 *  \param[in] rate bitrate used on the E1 trunk (e.g 16 for 16kbit).
 | 
				
			||||||
 | 
					 *  \param[in] offset bit offset of the E1 subslot (e.g. 4 for the third 16k subslot).
 | 
				
			||||||
 | 
					 *  \returns string containing the endpoint name (e.g. ds/e1-1/s-1/su16-4). */
 | 
				
			||||||
 | 
					const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
 | 
				
			||||||
 | 
									  uint8_t rate, uint8_t offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* See also comment in libosmo-mgcp, mgcp_client.c, gen_e1_epname() */
 | 
				
			||||||
 | 
						const uint8_t valid_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
 | 
				
			||||||
 | 
						const uint8_t valid_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t i;
 | 
				
			||||||
 | 
						bool rate_offs_valid = false;
 | 
				
			||||||
 | 
						char *epname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						epname =
 | 
				
			||||||
 | 
						    talloc_asprintf(ctx, "ds/e1-%u/s-%u/su%u-%u@%s", trunk_id, ts, rate, offset,
 | 
				
			||||||
 | 
								    mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
 | 
						if (!epname) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Cannot compose MGCP e1-endpoint name!\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if the supplied rate/offset pair resembles a valid combination */
 | 
				
			||||||
 | 
						for (i = 0; i < sizeof(valid_rates); i++) {
 | 
				
			||||||
 | 
							if (valid_rates[i] == rate && valid_offsets[i] == offset)
 | 
				
			||||||
 | 
								rate_offs_valid = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!rate_offs_valid) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "Cannot compose MGCP e1-endpoint name (%s), rate(%u)/offset(%u) combination is invalid!\n", epname,
 | 
				
			||||||
 | 
							     rate, offset);
 | 
				
			||||||
 | 
							talloc_free(epname);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* An E1 line has a maximum of 32 timeslots, while the first (ts=0) is
 | 
				
			||||||
 | 
						 * reserverd for framing and alignment, so we can not use it here. */
 | 
				
			||||||
 | 
						if (ts == 0 || ts > 31) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "Cannot compose MGCP e1-endpoint name (%s), E1-timeslot number (%u) is invalid!\n", epname, ts);
 | 
				
			||||||
 | 
							talloc_free(epname);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return epname;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending * mgcp_client_pending_add(
 | 
					struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			||||||
					struct mgcp_client *mgcp,
 | 
										struct mgcp_client *mgcp,
 | 
				
			||||||
					mgcp_trans_id_t trans_id,
 | 
										mgcp_trans_id_t trans_id,
 | 
				
			||||||
@@ -906,6 +976,9 @@ struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			|||||||
	struct mgcp_response_pending *pending;
 | 
						struct mgcp_response_pending *pending;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pending = talloc_zero(mgcp, struct mgcp_response_pending);
 | 
						pending = talloc_zero(mgcp, struct mgcp_response_pending);
 | 
				
			||||||
 | 
						if (!pending)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pending->trans_id = trans_id;
 | 
						pending->trans_id = trans_id;
 | 
				
			||||||
	pending->response_cb = response_cb;
 | 
						pending->response_cb = response_cb;
 | 
				
			||||||
	pending->priv = priv;
 | 
						pending->priv = priv;
 | 
				
			||||||
@@ -925,7 +998,7 @@ struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			|||||||
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
					int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			||||||
		   mgcp_response_cb_t response_cb, void *priv)
 | 
							   mgcp_response_cb_t response_cb, void *priv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_response_pending *pending;
 | 
						struct mgcp_response_pending *pending = NULL;
 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -937,7 +1010,14 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pending = mgcp_client_pending_add(mgcp, trans_id, response_cb, priv);
 | 
						/* Do not allocate a dummy 'mgcp_response_pending' entry */
 | 
				
			||||||
 | 
						if (response_cb != NULL) {
 | 
				
			||||||
 | 
							pending = mgcp_client_pending_add(mgcp, trans_id, response_cb, priv);
 | 
				
			||||||
 | 
							if (!pending) {
 | 
				
			||||||
 | 
								talloc_free(msg);
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msgb_l2len(msg) > 4096) {
 | 
						if (msgb_l2len(msg) > 4096) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -959,9 +1039,13 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mgcp_tx_error:
 | 
					mgcp_tx_error:
 | 
				
			||||||
 | 
						if (!pending)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						/* Dequeue pending response, it's going to be free()d */
 | 
				
			||||||
 | 
						llist_del(&pending->entry);
 | 
				
			||||||
	/* Pass NULL to response cb to indicate an error */
 | 
						/* Pass NULL to response cb to indicate an error */
 | 
				
			||||||
	mgcp_client_handle_response(mgcp, pending, NULL);
 | 
						mgcp_client_handle_response(mgcp, pending, NULL);
 | 
				
			||||||
	return -1;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Cancel a pending transaction.
 | 
					/*! Cancel a pending transaction.
 | 
				
			||||||
@@ -1050,7 +1134,8 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	char local_ip[INET_ADDRSTRLEN];
 | 
						char local_ip[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						int local_ip_family, audio_ip_family;
 | 
				
			||||||
	const char *codec;
 | 
						const char *codec;
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1067,10 +1152,21 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						local_ip_family = osmo_ip_str_type(local_ip);
 | 
				
			||||||
 | 
						if (local_ip_family == AF_UNSPEC) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						audio_ip_family = osmo_ip_str_type(mgcp_msg->audio_ip);
 | 
				
			||||||
 | 
						if (audio_ip_family == AF_UNSPEC) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add owner/creator (SDP) */
 | 
						/* Add owner/creator (SDP) */
 | 
				
			||||||
	rc += msgb_printf(msg, "o=- %x 23 IN IP4 %s\r\n",
 | 
						rc += msgb_printf(msg, "o=- %x 23 IN IP%c %s\r\n", mgcp_msg->call_id,
 | 
				
			||||||
			  mgcp_msg->call_id, local_ip);
 | 
								  local_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
 | 
								  local_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add session name (none) */
 | 
						/* Add session name (none) */
 | 
				
			||||||
	rc += msgb_printf(msg, "s=-\r\n");
 | 
						rc += msgb_printf(msg, "s=-\r\n");
 | 
				
			||||||
@@ -1088,7 +1184,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rc += msgb_printf(msg, "c=IN IP4 %s\r\n", mgcp_msg->audio_ip);
 | 
						rc += msgb_printf(msg, "c=IN IP%c %s\r\n",
 | 
				
			||||||
 | 
								  audio_ip_family == AF_INET6 ? '6' : '4',
 | 
				
			||||||
 | 
								  mgcp_msg->audio_ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add time description, active time (SDP) */
 | 
						/* Add time description, active time (SDP) */
 | 
				
			||||||
	rc += msgb_printf(msg, "t=0 0\r\n");
 | 
						rc += msgb_printf(msg, "t=0 0\r\n");
 | 
				
			||||||
@@ -1206,6 +1304,7 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
			     "Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
								     "Endpoint name (%s) lacks separator (@), can not generate MGCP message\n",
 | 
				
			||||||
			     mgcp_msg->endpoint);
 | 
								     mgcp_msg->endpoint);
 | 
				
			||||||
			msgb_free(msg);
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
 | 
							rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@
 | 
				
			|||||||
#include <osmocom/core/fsm.h>
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
#include <osmocom/core/byteswap.h>
 | 
					#include <osmocom/core/byteswap.h>
 | 
				
			||||||
#include <osmocom/core/tdef.h>
 | 
					#include <osmocom/core/tdef.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -235,8 +236,6 @@ static void fill_event_names()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* T_defs is used to obtain an (Osmocom specific) T2427001: timeout for an MGCP response (note, 2427 corresponds to the
 | 
					 | 
				
			||||||
 * default MGCP port in osmo-mgw). */
 | 
					 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
					static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
				
			||||||
@@ -468,14 +467,12 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ci->pending = false;
 | 
						ci->pending = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_info = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (ci->verb) {
 | 
						switch (ci->verb) {
 | 
				
			||||||
	case MGCP_VERB_CRCX:
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
		/* If we sent a wildcarded endpoint name on CRCX, we need to store the resulting endpoint
 | 
							/* If we sent a wildcarded endpoint name on CRCX, we need to store the resulting endpoint
 | 
				
			||||||
		 * name here. Also, we receive the MGW's RTP port information. */
 | 
							 * name here. Also, we receive the MGW's RTP port information. */
 | 
				
			||||||
		rtp_info = data;
 | 
					 | 
				
			||||||
		OSMO_ASSERT(rtp_info);
 | 
					 | 
				
			||||||
		ci->got_port_info = true;
 | 
					 | 
				
			||||||
		ci->rtp_info = *rtp_info;
 | 
					 | 
				
			||||||
		osmo_strlcpy(ci->mgcp_ci_str, mgcp_conn_get_ci(ci->mgcp_client_fi),
 | 
							osmo_strlcpy(ci->mgcp_ci_str, mgcp_conn_get_ci(ci->mgcp_client_fi),
 | 
				
			||||||
			sizeof(ci->mgcp_ci_str));
 | 
								sizeof(ci->mgcp_ci_str));
 | 
				
			||||||
		if (rtp_info->endpoint[0]) {
 | 
							if (rtp_info->endpoint[0]) {
 | 
				
			||||||
@@ -485,6 +482,15 @@ static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			|||||||
				return;
 | 
									return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ci->ep->first_crcx_complete = true;
 | 
							ci->ep->first_crcx_complete = true;
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtp_info);
 | 
				
			||||||
 | 
							/* fall through */
 | 
				
			||||||
 | 
						case MGCP_VERB_MDCX:
 | 
				
			||||||
 | 
							/* Always update the received RTP ip/port information, since MGW
 | 
				
			||||||
 | 
							 * may provide new one after remote end params changed */
 | 
				
			||||||
 | 
							if (rtp_info) {
 | 
				
			||||||
 | 
								ci->got_port_info = true;
 | 
				
			||||||
 | 
								ci->rtp_info = *rtp_info;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -517,17 +523,33 @@ const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgc
 | 
				
			|||||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct mgcp_conn_peer *rtp_info;
 | 
						const struct mgcp_conn_peer *rtp_info;
 | 
				
			||||||
 | 
						int family;
 | 
				
			||||||
	struct sockaddr_in *sin;
 | 
						struct sockaddr_in *sin;
 | 
				
			||||||
 | 
						struct sockaddr_in6 *sin6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 | 
						rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 | 
				
			||||||
	if (!rtp_info)
 | 
						if (!rtp_info)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sin = (struct sockaddr_in *)dest;
 | 
						family = osmo_ip_str_type(rtp_info->addr);
 | 
				
			||||||
 | 
						switch (family) {
 | 
				
			||||||
        sin->sin_family = AF_INET;
 | 
						case AF_INET:
 | 
				
			||||||
        sin->sin_addr.s_addr = inet_addr(rtp_info->addr);
 | 
							sin = (struct sockaddr_in *)dest;
 | 
				
			||||||
        sin->sin_port = osmo_ntohs(rtp_info->port);
 | 
							sin->sin_family = AF_INET;
 | 
				
			||||||
 | 
							sin->sin_port = osmo_ntohs(rtp_info->port);
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET, rtp_info->addr, &sin->sin_addr) != 1)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case AF_INET6:
 | 
				
			||||||
 | 
							sin6 = (struct sockaddr_in6 *)dest;
 | 
				
			||||||
 | 
							sin6->sin6_family = AF_INET6;
 | 
				
			||||||
 | 
							sin6->sin6_port = osmo_ntohs(rtp_info->port);
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET6, rtp_info->addr, &sin6->sin6_addr) != 1)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -547,7 +569,7 @@ bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct osmo_tdef_state_timeout osmo_mgcpc_ep_fsm_timeouts[32] = {
 | 
					static const struct osmo_tdef_state_timeout osmo_mgcpc_ep_fsm_timeouts[32] = {
 | 
				
			||||||
	[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=2427001 },
 | 
						[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=-2427 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.
 | 
					/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
#include <osmocom/core/byteswap.h>
 | 
					#include <osmocom/core/byteswap.h>
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Context information, this is attached to the priv pointer of the FSM and
 | 
					/* Context information, this is attached to the priv pointer of the FSM and
 | 
				
			||||||
 * is also handed back when dispatcheing events to the parent FSM. This is
 | 
					 * is also handed back when dispatcheing events to the parent FSM. This is
 | 
				
			||||||
@@ -522,8 +523,8 @@ static void fsm_cleanup_cb(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause ca
 | 
				
			|||||||
	 * connection. This is not the normal case. The user should always use
 | 
						 * connection. This is not the normal case. The user should always use
 | 
				
			||||||
	 * mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
 | 
						 * mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
 | 
				
			||||||
	if (strlen(mgcp_ctx->conn_id)) {
 | 
						if (strlen(mgcp_ctx->conn_id)) {
 | 
				
			||||||
		LOGPFSML(fi, LOGL_ERROR,
 | 
							LOGPFSML(fi, LOGL_NOTICE,
 | 
				
			||||||
			 "MGW/DLCX: abrupt FSM termination with connections still present, sending unconditional DLCX...\n");
 | 
								 "MGW/DLCX: FSM termination with connections still present, sending unconditional DLCX...\n");
 | 
				
			||||||
		msg = make_dlcx_msg(mgcp_ctx);
 | 
							msg = make_dlcx_msg(mgcp_ctx);
 | 
				
			||||||
		if (!msg)
 | 
							if (!msg)
 | 
				
			||||||
			LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
 | 
								LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
 | 
				
			||||||
@@ -607,14 +608,16 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_ctx *mgcp_ctx;
 | 
						struct mgcp_ctx *mgcp_ctx;
 | 
				
			||||||
	struct osmo_fsm_inst *fi;
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
	struct in_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(parent_fi);
 | 
						OSMO_ASSERT(parent_fi);
 | 
				
			||||||
	OSMO_ASSERT(mgcp);
 | 
						OSMO_ASSERT(mgcp);
 | 
				
			||||||
	OSMO_ASSERT(conn_peer);
 | 
						OSMO_ASSERT(conn_peer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if IP/Port information in conn info makes sense */
 | 
						/* Check if IP/Port information in conn info makes sense */
 | 
				
			||||||
	if (conn_peer->port && inet_aton(conn_peer->addr, &ip_test) == 0)
 | 
						if (conn_peer->port && inet_pton(osmo_ip_str_type(conn_peer->addr),
 | 
				
			||||||
 | 
										 conn_peer->addr, &ip_test) != 1)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate and configure a new fsm instance */
 | 
						/* Allocate and configure a new fsm instance */
 | 
				
			||||||
@@ -644,7 +647,7 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(fi);
 | 
						OSMO_ASSERT(fi);
 | 
				
			||||||
	struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
						struct mgcp_ctx *mgcp_ctx = fi->priv;
 | 
				
			||||||
	struct in_addr ip_test;
 | 
						struct in6_addr ip_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(mgcp_ctx);
 | 
						OSMO_ASSERT(mgcp_ctx);
 | 
				
			||||||
	OSMO_ASSERT(conn_peer);
 | 
						OSMO_ASSERT(conn_peer);
 | 
				
			||||||
@@ -668,8 +671,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
		LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, port == 0\n");
 | 
							LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, port == 0\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (inet_aton(conn_peer->addr, &ip_test) == 0) {
 | 
						if (inet_pton(osmo_ip_str_type(conn_peer->addr), conn_peer->addr, &ip_test) != 1) {
 | 
				
			||||||
		LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address == 0.0.0.0\n");
 | 
							LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address %s\n", conn_peer->addr);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,9 +36,10 @@ void *global_mgcp_client_ctx = NULL;
 | 
				
			|||||||
struct mgcp_client_conf *global_mgcp_client_conf = NULL;
 | 
					struct mgcp_client_conf *global_mgcp_client_conf = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "mgw local-ip A.B.C.D",
 | 
					      "mgw local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "local bind to connect to MGW from\n"
 | 
					      MGW_STR "local bind to connect to MGW from\n"
 | 
				
			||||||
      "local bind IP address\n")
 | 
					      "local bind IPv4 address\n"
 | 
				
			||||||
 | 
					      "local bind IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						if (!global_mgcp_client_conf)
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
							return CMD_ERR_NOTHING_TODO;
 | 
				
			||||||
@@ -69,9 +70,10 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
 | 
				
			|||||||
		 "local bind port\n")
 | 
							 "local bind port\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
					DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
				
			||||||
      "mgw remote-ip A.B.C.D",
 | 
					      "mgw remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "remote IP address to reach the MGW at\n"
 | 
					      MGW_STR "remote IP address to reach the MGW at\n"
 | 
				
			||||||
      "remote IP address\n")
 | 
					      "remote IPv4 address\n"
 | 
				
			||||||
 | 
					      "remote IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!global_mgcp_client_conf)
 | 
						if (!global_mgcp_client_conf)
 | 
				
			||||||
		return CMD_ERR_NOTHING_TODO;
 | 
							return CMD_ERR_NOTHING_TODO;
 | 
				
			||||||
@@ -188,21 +190,21 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
 | 
				
			|||||||
	global_mgcp_client_ctx = talloc_ctx;
 | 
						global_mgcp_client_ctx = talloc_ctx;
 | 
				
			||||||
	global_mgcp_client_conf = conf;
 | 
						global_mgcp_client_conf = conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_element(node, &cfg_mgw_local_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_local_ip_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_remote_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_remote_ip_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_remote_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_remote_port_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* deprecated 'mgcpgw' commands */
 | 
						/* deprecated 'mgcpgw' commands */
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_local_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_local_port_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_remote_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_remote_ip_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_remote_port_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_remote_port_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);
 | 
				
			||||||
	install_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fsm_vty_add_cmds();
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMOVTY_CFLAGS) \
 | 
						$(LIBOSMOVTY_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMONETIF_CFLAGS) \
 | 
						$(LIBOSMONETIF_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_CFLAGS) \
 | 
				
			||||||
	$(COVERAGE_CFLAGS) \
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,6 +20,8 @@ AM_LDFLAGS = \
 | 
				
			|||||||
	$(LIBOSMOGSM_LIBS) \
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
	$(LIBOSMOVTY_LIBS) \
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
	$(LIBOSMONETIF_LIBS) \
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_LIBS) \
 | 
				
			||||||
	$(COVERAGE_LDFLAGS) \
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,5 +44,8 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_conn.c \
 | 
						mgcp_conn.c \
 | 
				
			||||||
	mgcp_stat.c \
 | 
						mgcp_stat.c \
 | 
				
			||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
 | 
						mgcp_trunk.c \
 | 
				
			||||||
	mgcp_ctrl.c \
 | 
						mgcp_ctrl.c \
 | 
				
			||||||
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
 | 
						mgcp_e1.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,13 @@
 | 
				
			|||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function to dump codec information of a specified codec to a printable
 | 
					/* Helper function to dump codec information of a specified codec to a printable
 | 
				
			||||||
@@ -279,36 +284,16 @@ error:
 | 
				
			|||||||
 * Helper function for mgcp_codec_decide() */
 | 
					 * Helper function for mgcp_codec_decide() */
 | 
				
			||||||
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
					static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char codec_name[64];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* A codec name must be set, if not, this might mean that the codec
 | 
						/* A codec name must be set, if not, this might mean that the codec
 | 
				
			||||||
	 * (payload type) that was assigned is unknown to us so we must stop
 | 
						 * (payload type) that was assigned is unknown to us so we must stop
 | 
				
			||||||
	 * here. */
 | 
						 * here. */
 | 
				
			||||||
	if (!codec->subtype_name)
 | 
						if (!codec->subtype_name)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We now extract the codec_name (letters before the /, e.g. "GSM"
 | 
						/* FIXME: implement meaningful checks to make sure that the given codec
 | 
				
			||||||
	 * from the audio name that is stored in the trunk configuration.
 | 
						 * is compatible with the given endpoint */
 | 
				
			||||||
	 * We do not compare to the full audio_name because we expect that
 | 
					 | 
				
			||||||
	 * "GSM", "GSM/8000" and "GSM/8000/1" are all compatible when the
 | 
					 | 
				
			||||||
	 * audio name of the codec is set to "GSM" */
 | 
					 | 
				
			||||||
	if (sscanf(endp->tcfg->audio_name, "%63[^/]/%*d/%*d", codec_name) < 1)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Finally we check if the subtype_name we have generated from the
 | 
						return true;
 | 
				
			||||||
	 * audio_name in the trunc struct patches the codec_name of the
 | 
					 | 
				
			||||||
	 * given codec */
 | 
					 | 
				
			||||||
	if (strcasecmp(codec_name, codec->subtype_name) == 0)
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: It is questinable that the method to pick a compatible
 | 
					 | 
				
			||||||
	 * codec can work properly. Since this useses tcfg->audio_name, as
 | 
					 | 
				
			||||||
	 * a reference, which is set to "AMR/8000" permanently.
 | 
					 | 
				
			||||||
	 * tcfg->audio_name must be updated by the first connection that
 | 
					 | 
				
			||||||
	 * has been made on an endpoint, so that the second connection
 | 
					 | 
				
			||||||
	 * can make a meaningful decision here */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Decide for one suitable codec
 | 
					/*! Decide for one suitable codec
 | 
				
			||||||
@@ -335,7 +320,7 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
						for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
				
			||||||
		/* When no transcoding is available, avoid codecs that would
 | 
							/* When no transcoding is available, avoid codecs that would
 | 
				
			||||||
		 * require transcoding. */
 | 
							 * require transcoding. */
 | 
				
			||||||
		if (endp->tcfg->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
 | 
							if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
 | 
								LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
 | 
				
			||||||
			     rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
 | 
								     rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
@@ -451,3 +436,28 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return codec_dst->payload_type;
 | 
						return codec_dst->payload_type;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find the payload type number configured for a specific codec by SDP.
 | 
				
			||||||
 | 
					 * For example, IuUP gets assigned a payload type number, and the endpoint needs to translate that to the number
 | 
				
			||||||
 | 
					 * assigned to "AMR" on the other conn (by a=rtpmap:N).
 | 
				
			||||||
 | 
					 * \param conn  The side of an endpoint to get the payload type number for (to translate the payload type number to).
 | 
				
			||||||
 | 
					 * \param subtype_name  SDP codec name without parameters (e.g. "AMR").
 | 
				
			||||||
 | 
					 * \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 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)) {
 | 
				
			||||||
 | 
								if (match_nr) {
 | 
				
			||||||
 | 
									match_nr--;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return &conn->end.codecs[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,11 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/gsm/gsm_utils.h>
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
@@ -197,7 +199,7 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	/* Initialize watchdog */
 | 
						/* Initialize watchdog */
 | 
				
			||||||
	osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
 | 
						osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
 | 
				
			||||||
	mgcp_conn_watchdog_kick(conn);
 | 
						mgcp_conn_watchdog_kick(conn);
 | 
				
			||||||
	llist_add(&conn->entry, &endp->conns);
 | 
						mgcp_endp_add_conn(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return conn;
 | 
						return conn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -254,10 +256,9 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
aggregate_rtp_conn_stats(struct mgcp_trunk_config *trunk, struct mgcp_conn_rtp *conn_rtp)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *all_stats = trunk->all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
	struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
						struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (all_stats == NULL || conn_stats == NULL)
 | 
						if (all_stats == NULL || conn_stats == NULL)
 | 
				
			||||||
@@ -288,15 +289,9 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
				
			|||||||
	if (!conn)
 | 
						if (!conn)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Run endpoint cleanup action. By this we inform the endpoint about
 | 
					 | 
				
			||||||
	 * the removal of the connection and allow it to clean up its inner
 | 
					 | 
				
			||||||
	 * state accordingly */
 | 
					 | 
				
			||||||
	if (endp->type->cleanup_cb)
 | 
					 | 
				
			||||||
		endp->type->cleanup_cb(endp, conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		aggregate_rtp_conn_stats(endp->tcfg, &conn->u.rtp);
 | 
							aggregate_rtp_conn_stats(endp, &conn->u.rtp);
 | 
				
			||||||
		mgcp_rtp_conn_cleanup(&conn->u.rtp);
 | 
							mgcp_rtp_conn_cleanup(&conn->u.rtp);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -307,7 +302,8 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_timer_del(&conn->watchdog);
 | 
						osmo_timer_del(&conn->watchdog);
 | 
				
			||||||
	llist_del(&conn->entry);
 | 
						mgcp_endp_remove_conn(endp, conn);
 | 
				
			||||||
 | 
						/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
 | 
				
			||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -348,6 +344,7 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
				
			|||||||
char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
					char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
						static char str[sizeof(conn->name)+sizeof(conn->id)+256];
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn) {
 | 
				
			||||||
		snprintf(str, sizeof(str), "(null connection)");
 | 
							snprintf(str, sizeof(str), "(null connection)");
 | 
				
			||||||
@@ -361,7 +358,7 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			|||||||
			 "rtp:%u rtcp:%u)",
 | 
								 "rtp:%u rtcp:%u)",
 | 
				
			||||||
			 conn->name,
 | 
								 conn->name,
 | 
				
			||||||
			 conn->id,
 | 
								 conn->id,
 | 
				
			||||||
			 inet_ntoa(conn->u.rtp.end.addr),
 | 
								 osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtp_port),
 | 
								 ntohs(conn->u.rtp.end.rtp_port),
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtcp_port));
 | 
								 ntohs(conn->u.rtp.end.rtcp_port));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -397,3 +394,13 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										685
									
								
								src/libosmo-mgcp/mgcp_e1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										685
									
								
								src/libosmo-mgcp/mgcp_e1.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,685 @@
 | 
				
			|||||||
 | 
					/* E1 traffic handling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Philipp Maier
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/abis/abis.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/trau/trau_sync.h>
 | 
				
			||||||
 | 
					#include <osmocom/trau/trau_frame.h>
 | 
				
			||||||
 | 
					#include <osmocom/trau/trau_rtp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
 | 
					#include <osmocom/codec/codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEBUG_BITS_MAX 80
 | 
				
			||||||
 | 
					#define DEBUG_BYTES_MAX 40
 | 
				
			||||||
 | 
					#define DEBUG_E1_TS 0
 | 
				
			||||||
 | 
					#define E1_TS_BYTES 160
 | 
				
			||||||
 | 
					#define E1_TRAU_BITS 320
 | 
				
			||||||
 | 
					#define E1_TRAU_BITS_MSGB 2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct mgcp_config *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct e1inp_line_ops dummy_e1_line_ops = {
 | 
				
			||||||
 | 
						.sign_link_up = NULL,
 | 
				
			||||||
 | 
						.sign_link_down = NULL,
 | 
				
			||||||
 | 
						.sign_link = NULL,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* EFR idle frame */
 | 
				
			||||||
 | 
					static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 1, 1, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									      1, 0, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
 | 
									      1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* FR idle frame */
 | 
				
			||||||
 | 
					static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 1, 1, 1, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									     1, 0, 0, 0, 0, 0, 1, 0,
 | 
				
			||||||
 | 
									     1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
 | 
				
			||||||
 | 
					static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									       0, 0, 0, 0, 0, 0, 0, 0,
 | 
				
			||||||
 | 
									       1, 0, 1, 1, 1, 0, 0, 0,
 | 
				
			||||||
 | 
									       0, 0, 0, 0, 1, 0, 0, 0,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 0,
 | 
				
			||||||
 | 
									       1, 1, 1, 1, 1, 1, 1, 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
 | 
				
			||||||
 | 
					 * run empty. In order to make sure that the TRAU frame transmission continues
 | 
				
			||||||
 | 
					 * we generate idle TRAU frames here. */
 | 
				
			||||||
 | 
					static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp = user_data;
 | 
				
			||||||
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
 | 
				
			||||||
 | 
						uint8_t *ptr;
 | 
				
			||||||
 | 
						const uint8_t *ptr_ft;
 | 
				
			||||||
 | 
						enum osmo_trau_frame_type ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_MUX_EMPTY_CTR]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Choose an appropiate idle frame type */
 | 
				
			||||||
 | 
						ft = endp->e1.trau_rtp_st->type;
 | 
				
			||||||
 | 
						switch (ft) {
 | 
				
			||||||
 | 
						case OSMO_TRAU16_FT_FR:
 | 
				
			||||||
 | 
							ptr_ft = idle_tf_fr;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OSMO_TRAU16_FT_EFR:
 | 
				
			||||||
 | 
							ptr_ft = idle_tf_efr;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							/* FIXME: What about 8k subslots and AMR frames? */
 | 
				
			||||||
 | 
							ptr_ft = idle_tf_spch;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Put the replacement into a message buffer and enqueue it into the
 | 
				
			||||||
 | 
						 * I.460 multiplexer */
 | 
				
			||||||
 | 
						ptr = msgb_put(msg, E1_TRAU_BITS);
 | 
				
			||||||
 | 
						memcpy(ptr, ptr_ft, E1_TRAU_BITS);
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg),
 | 
				
			||||||
 | 
							 osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg)));
 | 
				
			||||||
 | 
						osmo_i460_mux_enqueue(endp->e1.schan, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */
 | 
				
			||||||
 | 
					static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
 | 
				
			||||||
 | 
									  unsigned int num_bits)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp = user_data;
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u bits from subslot: %s...\n", num_bits,
 | 
				
			||||||
 | 
							 osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->e1.trau_sync_fi);
 | 
				
			||||||
 | 
						osmo_trau_sync_rx_ubits(endp->e1.trau_sync_fi, bits, num_bits);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* called for each synchronized TRAU frame received; decode frame + convert to RTP
 | 
				
			||||||
 | 
					 * (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */
 | 
				
			||||||
 | 
					static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc(RTP_BUF_SIZE, "RTP-rx-from-E1");
 | 
				
			||||||
 | 
						unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp = user_data;
 | 
				
			||||||
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
 | 
						struct mgcp_conn *conn_dst;
 | 
				
			||||||
 | 
						struct osmo_trau_frame fr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!bits || num_bits == 0)
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u TRAU frame bits from E1 subslot: %s...\n",
 | 
				
			||||||
 | 
							 num_bits, osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Decode TRAU frame */
 | 
				
			||||||
 | 
						switch (endp->e1.scd.rate) {
 | 
				
			||||||
 | 
						case OSMO_I460_RATE_8k:
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 8k trau frame...\n");
 | 
				
			||||||
 | 
							rc = osmo_trau_frame_decode_8k(&fr, bits, OSMO_TRAU_DIR_UL);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OSMO_I460_RATE_16k:
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 16k trau frame...\n");
 | 
				
			||||||
 | 
							rc = osmo_trau_frame_decode_16k(&fr, bits, OSMO_TRAU_DIR_UL);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							/* TRAU frames only exist in 8K or 16K subslots. */
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to decode trau frame\n");
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if the payload type is supported and what the expected lenth
 | 
				
			||||||
 | 
						 * of the RTP payload will be. */
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoded trau frame type: %s\n",
 | 
				
			||||||
 | 
							 osmo_trau_frame_type_name(fr.type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Convert decoded trau frame to RTP frame */
 | 
				
			||||||
 | 
						struct osmo_trau2rtp_state t2rs = {
 | 
				
			||||||
 | 
							.type = fr.type,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);
 | 
				
			||||||
 | 
						if (rc <= 0) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to convert trau frame to RTP audio\n");
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_put(msg, rtp_hdr_len + rc);
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: encoded %u bytes of RTP audio: %s\n", rc,
 | 
				
			||||||
 | 
							 osmo_hexdump(msgb_data(msg) + rtp_hdr_len, msgb_length(msg) - rtp_hdr_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Forward RTP data to IP */
 | 
				
			||||||
 | 
						conn_dst = llist_first_entry(&endp->conns, struct mgcp_conn, entry);
 | 
				
			||||||
 | 
						if (!conn_dst) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "E1-I.460-RX: unable to forward RTP audio data from E1: no connection to forward an incoming RTP packet to\n");
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn_dst->type == MGCP_CONN_TYPE_RTP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					skip:
 | 
				
			||||||
 | 
						rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_RX_FAIL_CTR]);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Function to handle outgoing E1 traffic */
 | 
				
			||||||
 | 
					static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc(E1_TS_BYTES, "E1-TX-timeslot-bytes");
 | 
				
			||||||
 | 
						uint8_t *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get E1 frame from I.460 multiplexer */
 | 
				
			||||||
 | 
						ptr = msgb_put(msg, E1_TS_BYTES);
 | 
				
			||||||
 | 
						osmo_i460_mux_out(&trunk->e1.i460_ts[ts->num - 1], ptr, E1_TS_BYTES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG_E1_TS == 1
 | 
				
			||||||
 | 
						LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-TX: (ts:%u) sending %u bytes: %s...\n", ts->num, msgb_length(msg),
 | 
				
			||||||
 | 
							  osmo_hexdump_nospc(msgb_data(msg),
 | 
				
			||||||
 | 
									     msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						/* Hand data over to the E1 stack */
 | 
				
			||||||
 | 
						msgb_enqueue(&ts->raw.tx_queue, msg);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback function to handle incoming E1 traffic */
 | 
				
			||||||
 | 
					static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find associated trunk */
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
 | 
				
			||||||
 | 
						if (!trunk) {
 | 
				
			||||||
 | 
							LOGP(DE1, LOGL_DEBUG, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if the incoming data looks sane */
 | 
				
			||||||
 | 
						if (msgb_length(msg) != E1_TS_BYTES) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_NOTICE,
 | 
				
			||||||
 | 
								  "E1-RX: (ts:%u) expected length is %u, actual length is %u!\n", ts->num, E1_TS_BYTES,
 | 
				
			||||||
 | 
								  msgb_length(msg));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#if DEBUG_E1_TS == 1
 | 
				
			||||||
 | 
						LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-RX: (ts:%u) receiving %u bytes: %s...\n", ts->num,
 | 
				
			||||||
 | 
							  msgb_length(msg), osmo_hexdump_nospc(msgb_data(msg),
 | 
				
			||||||
 | 
											       msgb_length(msg) >
 | 
				
			||||||
 | 
											       DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Hand data over to the I.460 demultiplexer. */
 | 
				
			||||||
 | 
						osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Trigger sending of pending E1 traffic */
 | 
				
			||||||
 | 
						e1_send(ts, trunk);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*! Each timeslot needs only to be configured once. The Timeslot then
 | 
				
			||||||
 | 
						 *  stays open and permanently receives data. It is then up to the
 | 
				
			||||||
 | 
						 *  I.460 demultiplexer to add/remove subchannels as needed. It is
 | 
				
			||||||
 | 
						 *  allowed to call this function multiple times since we check if the
 | 
				
			||||||
 | 
						 *  timeslot is already configured. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct e1inp_line *e1_line;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
 | 
				
			||||||
 | 
						cfg = trunk->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (trunk->e1.ts_in_use[ts_nr - 1]) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u already set up, skipping...\n", ts_nr);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get E1 line */
 | 
				
			||||||
 | 
						e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
 | 
				
			||||||
 | 
						if (!e1_line) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "no such E1 line %u - check VTY config!\n",
 | 
				
			||||||
 | 
								  trunk->e1.vty_line_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Configure E1 timeslot */
 | 
				
			||||||
 | 
						rc = e1inp_ts_config_raw(&e1_line->ts[ts_nr - 1], e1_line, e1_recv_cb);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to put E1 timeslot %u in raw mode.\n", ts_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc = e1inp_line_update(e1_line);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1 timeslot %u set up successfully.\n", ts_nr);
 | 
				
			||||||
 | 
						trunk->e1.ts_in_use[ts_nr - 1] = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Determine a suitable TRAU frame type for a given codec */
 | 
				
			||||||
 | 
					static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,
 | 
				
			||||||
 | 
												uint8_t amr_ft, struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU16_FT_FR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU16_FT_EFR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU16_FT_HR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
 | 
								switch (amr_ft) {
 | 
				
			||||||
 | 
								case AMR_4_75:
 | 
				
			||||||
 | 
								case AMR_5_15:
 | 
				
			||||||
 | 
								case AMR_5_90:
 | 
				
			||||||
 | 
									return OSMO_TRAU8_AMR_LOW;
 | 
				
			||||||
 | 
								case AMR_6_70:
 | 
				
			||||||
 | 
									return OSMO_TRAU8_AMR_6k7;
 | 
				
			||||||
 | 
								case AMR_7_40:
 | 
				
			||||||
 | 
									return OSMO_TRAU8_AMR_7k4;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
										 "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);
 | 
				
			||||||
 | 
									return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return OSMO_TRAU16_FT_AMR;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
								 sdp_subtype_name);
 | 
				
			||||||
 | 
							return OSMO_TRAU_FT_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Determine a suitable TRAU frame type for a given codec */
 | 
				
			||||||
 | 
					static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,
 | 
				
			||||||
 | 
												  uint8_t amr_ft, struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strcmp(sdp_subtype_name, "GSM") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_8_HR;
 | 
				
			||||||
 | 
						else if (strcmp(sdp_subtype_name, "AMR") == 0) {
 | 
				
			||||||
 | 
							if (i460_rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
 | 
								switch (amr_ft) {
 | 
				
			||||||
 | 
								case AMR_4_75:
 | 
				
			||||||
 | 
								case AMR_5_15:
 | 
				
			||||||
 | 
								case AMR_5_90:
 | 
				
			||||||
 | 
									return OSMO_TRAU_SYNCP_8_AMR_LOW;
 | 
				
			||||||
 | 
								case AMR_6_70:
 | 
				
			||||||
 | 
									return OSMO_TRAU_SYNCP_8_AMR_6K7;
 | 
				
			||||||
 | 
								case AMR_7_40:
 | 
				
			||||||
 | 
									return OSMO_TRAU_SYNCP_8_AMR_7K4;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
										 "E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);
 | 
				
			||||||
 | 
									return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
 | 
				
			||||||
 | 
								 sdp_subtype_name);
 | 
				
			||||||
 | 
							return OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find out if a given TRAU frame type is AMR */
 | 
				
			||||||
 | 
					static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ft) {
 | 
				
			||||||
 | 
						case OSMO_TRAU16_FT_AMR:
 | 
				
			||||||
 | 
						case OSMO_TRAU8_AMR_LOW:
 | 
				
			||||||
 | 
						case OSMO_TRAU8_AMR_6k7:
 | 
				
			||||||
 | 
						case OSMO_TRAU8_AMR_7k4:
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* !Equip E1 endpoint with I.460 mux resources.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to equip
 | 
				
			||||||
 | 
					 *  \param[in] ts E1 timeslot number.
 | 
				
			||||||
 | 
					 *  \param[in] ss E1 subslot number.
 | 
				
			||||||
 | 
					 *  \param[in] offset E1 bit offset.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
 | 
					int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						enum osmo_tray_sync_pat_id sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ts != 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ts != 0xFF);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ss != 0xFF);
 | 
				
			||||||
 | 
						OSMO_ASSERT(offs != 0xFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&endp->e1, 0, sizeof(endp->e1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp->e1.last_amr_ft = AMR_4_75;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up E1 line / timeslot */
 | 
				
			||||||
 | 
						rc = e1_init(endp->trunk, ts);
 | 
				
			||||||
 | 
						if (rc != 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up I.460 mux */
 | 
				
			||||||
 | 
						switch (e1_rates[ss]) {
 | 
				
			||||||
 | 
						case 64:
 | 
				
			||||||
 | 
							endp->e1.scd.rate = OSMO_I460_RATE_64k;
 | 
				
			||||||
 | 
							endp->e1.scd.demux.num_bits = 160 * 8;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 32:
 | 
				
			||||||
 | 
							endp->e1.scd.rate = OSMO_I460_RATE_32k;
 | 
				
			||||||
 | 
							endp->e1.scd.demux.num_bits = 80 * 8;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 16:
 | 
				
			||||||
 | 
							endp->e1.scd.rate = OSMO_I460_RATE_16k;
 | 
				
			||||||
 | 
							endp->e1.scd.demux.num_bits = 40 * 8;
 | 
				
			||||||
 | 
							sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 8:
 | 
				
			||||||
 | 
							endp->e1.scd.rate = OSMO_I460_RATE_8k;
 | 
				
			||||||
 | 
							endp->e1.scd.demux.num_bits = 20 * 8;
 | 
				
			||||||
 | 
							sync_pat_id = OSMO_TRAU_SYNCP_8_HR;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						endp->e1.scd.bit_offset = offs;
 | 
				
			||||||
 | 
						endp->e1.scd.demux.out_cb_bits = e1_i460_demux_bits_cb;
 | 
				
			||||||
 | 
						endp->e1.scd.demux.out_cb_bytes = NULL;
 | 
				
			||||||
 | 
						endp->e1.scd.demux.user_data = endp;
 | 
				
			||||||
 | 
						endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;
 | 
				
			||||||
 | 
						endp->e1.scd.mux.user_data = endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
 | 
				
			||||||
 | 
							 offs, e1_rates[ss], endp->e1.scd.demux.num_bits);
 | 
				
			||||||
 | 
						endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);
 | 
				
			||||||
 | 
						if (!endp->e1.schan) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 subchannel: failed!\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (endp->e1.scd.rate == OSMO_I460_RATE_16k || endp->e1.scd.rate == OSMO_I460_RATE_8k) {
 | 
				
			||||||
 | 
							/* TRAU frames are only specified for 16k and 8k subslots. For all other subslot
 | 
				
			||||||
 | 
							 * types the concept of TRAU frames does not apply. However, at the moment this
 | 
				
			||||||
 | 
							 * is the only format we currently support in osmo-mgw */
 | 
				
			||||||
 | 
							endp->e1.trau_sync_fi = osmo_trau_sync_alloc(endp, "trau-sync", sync_frame_out_cb, sync_pat_id, endp);
 | 
				
			||||||
 | 
							if (!endp->e1.trau_sync_fi) {
 | 
				
			||||||
 | 
								LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 TRAU frame sync: failed!\n");
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							endp->e1.trau_rtp_st = talloc_zero(endp->e1.trau_sync_fi, struct osmo_trau2rtp_state);
 | 
				
			||||||
 | 
							endp->e1.trau_rtp_st->type = OSMO_TRAU_FT_NONE;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "osmo-mgw currently only supports 16K and 8K subslots (TRAU frames)!\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Update E1 related parameters (codec and sync pattern).
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to update. */
 | 
				
			||||||
 | 
					void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
 | 
						enum osmo_tray_sync_pat_id sync_pat_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* In order to determine the codec, find the oldest connection on
 | 
				
			||||||
 | 
						 * the endpoint and use its codec information. Normally on an E1
 | 
				
			||||||
 | 
						 * endpoint no more than one connection should exist. */
 | 
				
			||||||
 | 
						conn = mgcp_conn_get_oldest(endp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
						codec = conn->u.rtp.end.codec;
 | 
				
			||||||
 | 
						OSMO_ASSERT(codec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update codec information */
 | 
				
			||||||
 | 
						endp->e1.trau_rtp_st->type =
 | 
				
			||||||
 | 
						    determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
 | 
				
			||||||
 | 
						endp->e1.last_codec = codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update sync pattern */
 | 
				
			||||||
 | 
						sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
 | 
				
			||||||
 | 
						osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Remove E1 resources from endpoint
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to release. */
 | 
				
			||||||
 | 
					void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (endp->e1.schan)
 | 
				
			||||||
 | 
							osmo_i460_subchan_del(endp->e1.schan);
 | 
				
			||||||
 | 
						if (endp->e1.trau_rtp_st)
 | 
				
			||||||
 | 
							talloc_free(endp->e1.trau_rtp_st);
 | 
				
			||||||
 | 
						if (endp->e1.trau_sync_fi)
 | 
				
			||||||
 | 
							osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&endp->e1, 0, sizeof(endp->e1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
 | 
				
			||||||
 | 
					 *  \param[in] endp related endpoint (does not take ownership).
 | 
				
			||||||
 | 
					 *  \param[in] codec configuration.
 | 
				
			||||||
 | 
					 *  \param[in] msg RTP message buffer (including RTP header).
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
 | 
					int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg_tf = msgb_alloc(E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
 | 
				
			||||||
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
 | 
				
			||||||
 | 
						unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
						struct osmo_trau_frame tf;
 | 
				
			||||||
 | 
						uint8_t amr_ft;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Extract AMR frame type from AMR head (if AMR is used) */
 | 
				
			||||||
 | 
						if (tf_type_is_amr(endp->e1.trau_rtp_st->type))
 | 
				
			||||||
 | 
							amr_ft = (msgb_data(msg)[rtp_hdr_len + 1] >> 3) & 0xf;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							amr_ft = 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Adapt TRAU frame type on codec changes */
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->e1.last_codec);
 | 
				
			||||||
 | 
						if (codec != endp->e1.last_codec || (amr_ft != 0xff && amr_ft != endp->e1.last_amr_ft)) {
 | 
				
			||||||
 | 
							endp->e1.trau_rtp_st->type =
 | 
				
			||||||
 | 
							    determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, amr_ft, endp);
 | 
				
			||||||
 | 
							endp->e1.last_codec = codec;
 | 
				
			||||||
 | 
							endp->e1.last_amr_ft = amr_ft;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (endp->e1.trau_rtp_st->type == OSMO_TRAU_FT_NONE)
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: using trau frame type for encoding: %s\n",
 | 
				
			||||||
 | 
							 osmo_trau_frame_type_name(endp->e1.trau_rtp_st->type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Convert from RTP to TRAU format */
 | 
				
			||||||
 | 
						msg->l2h = msgb_data(msg) + rtp_hdr_len;
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: decoding %u bytes of RTP audio to TRAU format: %s\n",
 | 
				
			||||||
 | 
							 msgb_length(msg), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
 | 
				
			||||||
 | 
						memset(&tf, 0, sizeof(tf));
 | 
				
			||||||
 | 
						tf.dir = OSMO_TRAU_DIR_DL;
 | 
				
			||||||
 | 
						rc = osmo_rtp2trau(&tf, msgb_l2(msg), msgb_l2len(msg), endp->e1.trau_rtp_st);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "E1-I.460-TX: failed to decode from RTP payload format to TRAU format\n");
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc = osmo_trau_frame_encode(msgb_data(msg_tf), msg_tf->data_len, &tf);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: failed to encode TRAU frame\n");
 | 
				
			||||||
 | 
							goto skip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_put(msg_tf, rc);
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg_tf),
 | 
				
			||||||
 | 
							 osmo_ubit_dump(msgb_data(msg_tf),
 | 
				
			||||||
 | 
									msgb_length(msg_tf) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg_tf)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enqueue data to I.460 multiplexer */
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->e1.schan);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->e1.trau_sync_fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_i460_mux_enqueue(endp->e1.schan, msg_tf);
 | 
				
			||||||
 | 
						LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: %u bits of audio enqued for E1 tx\n", msgb_length(msg_tf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					skip:
 | 
				
			||||||
 | 
						rate_ctr_inc(&rate_ctrs->ctr[E1_I460_TRAU_TX_FAIL_CTR]);
 | 
				
			||||||
 | 
						msgb_free(msg_tf);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/* Endpoint types */
 | 
					/* Endpoint types */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					 * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Author: Philipp Maier
 | 
					 * Author: Philipp Maier
 | 
				
			||||||
@@ -21,17 +21,95 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define E1_RATE_MAX 64
 | 
				
			||||||
 | 
					#define E1_OFFS_MAX 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Endpoint typeset definition */
 | 
					/* Endpoint typeset definition */
 | 
				
			||||||
const struct mgcp_endpoint_typeset ep_typeset = {
 | 
					const struct mgcp_endpoint_typeset ep_typeset = {
 | 
				
			||||||
	/* Specify endpoint properties for RTP endpoint */
 | 
						/* Specify endpoint properties for RTP endpoint */
 | 
				
			||||||
	.rtp.max_conns = 2,
 | 
						.rtp = {
 | 
				
			||||||
	.rtp.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
							.max_conns = 2,
 | 
				
			||||||
	.rtp.cleanup_cb = mgcp_cleanup_rtp_bridge_cb
 | 
							.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
 | 
				
			||||||
 | 
							.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						/* Specify endpoint properties for E1 endpoint */
 | 
				
			||||||
 | 
						.e1 = {
 | 
				
			||||||
 | 
							.max_conns = 1,
 | 
				
			||||||
 | 
							.dispatch_rtp_cb = mgcp_dispatch_e1_bridge_cb,
 | 
				
			||||||
 | 
							.cleanup_cb = mgcp_cleanup_e1_bridge_cb,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Generate virtual endpoint name from given parameters */
 | 
				
			||||||
 | 
					static char *gen_virtual_epname(void *ctx, const char *domain,
 | 
				
			||||||
 | 
								       unsigned int index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return talloc_asprintf(ctx, "%s%x@%s",
 | 
				
			||||||
 | 
							 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, index, domain);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Generate E1 endpoint name from given numeric parameters */
 | 
				
			||||||
 | 
					static char *gen_e1_epname(void *ctx, const char *domain, uint8_t trunk_nr,
 | 
				
			||||||
 | 
								   uint8_t ts_nr, uint8_t ss_nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int rate;
 | 
				
			||||||
 | 
						unsigned int offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ss_nr < sizeof(e1_rates));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rate = e1_rates[ss_nr];
 | 
				
			||||||
 | 
						offset = e1_offsets[ss_nr];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return talloc_asprintf(ctx, "%s%u/s-%u/su%u-%u@%s",
 | 
				
			||||||
 | 
								       MGCP_ENDPOINT_PREFIX_E1_TRUNK, trunk_nr, ts_nr,
 | 
				
			||||||
 | 
								       rate, offset, domain);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate an endpoint and set default values.
 | 
				
			||||||
 | 
					 *  \param[in] trunk configuration.
 | 
				
			||||||
 | 
					 *  \param[in] name endpoint index.
 | 
				
			||||||
 | 
					 *  \returns endpoint on success, NULL on failure. */
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
 | 
				
			||||||
 | 
									      unsigned int index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp = talloc_zero(trunk->endpoints, struct mgcp_endpoint);
 | 
				
			||||||
 | 
						if (!endp)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&endp->conns);
 | 
				
			||||||
 | 
						endp->cfg = trunk->cfg;
 | 
				
			||||||
 | 
						endp->trunk = trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							endp->type = &ep_typeset.rtp;
 | 
				
			||||||
 | 
							endp->name = gen_virtual_epname(endp, trunk->cfg->domain, index);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							endp->type = &ep_typeset.e1;
 | 
				
			||||||
 | 
							endp->name = gen_e1_epname(endp, trunk->cfg->domain,
 | 
				
			||||||
 | 
										   trunk->trunk_nr,
 | 
				
			||||||
 | 
										   index / MGCP_ENDP_E1_SUBSLOTS, index % MGCP_ENDP_E1_SUBSLOTS);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
 | 
				
			||||||
 | 
								   trunk->trunk_type, __FILE__, __LINE__);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return endp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! release endpoint, all open connections are closed.
 | 
					/*! release endpoint, all open connections are closed.
 | 
				
			||||||
 *  \param[in] endp endpoint to release */
 | 
					 *  \param[in] endp endpoint to release */
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
@@ -52,4 +130,555 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			|||||||
	talloc_free(endp->local_options.codec);
 | 
						talloc_free(endp->local_options.codec);
 | 
				
			||||||
	endp->local_options.codec = NULL;
 | 
						endp->local_options.codec = NULL;
 | 
				
			||||||
	endp->wildcarded_req = false;
 | 
						endp->wildcarded_req = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
 | 
				
			||||||
 | 
							mgcp_e1_endp_release(endp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
 | 
				
			||||||
 | 
					 * "ds/e1-") and write the epname without the prefix back to the memory
 | 
				
			||||||
 | 
					 * pointed at by epname. (per trunk the prefix is the same for all endpoints,
 | 
				
			||||||
 | 
					 * so no ambiguity is introduced) */
 | 
				
			||||||
 | 
					static void chop_epname_prefix(char *epname, const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t prefix_len;
 | 
				
			||||||
 | 
						switch (trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
 | 
				
			||||||
 | 
							if (strncmp
 | 
				
			||||||
 | 
							    (epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
 | 
				
			||||||
 | 
							     prefix_len) == 0)
 | 
				
			||||||
 | 
								memmove(epname, epname + prefix_len,
 | 
				
			||||||
 | 
									strlen(epname) - prefix_len + 1);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
 | 
				
			||||||
 | 
							if (strncmp
 | 
				
			||||||
 | 
							    (epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
 | 
				
			||||||
 | 
							     prefix_len) == 0)
 | 
				
			||||||
 | 
								memmove(epname, epname + prefix_len,
 | 
				
			||||||
 | 
									strlen(epname) - prefix_len + 1);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the endpoint name contains a suffix (e.g. "@mgw") and truncate
 | 
				
			||||||
 | 
					 * epname by writing a '\0' char where the suffix starts. */
 | 
				
			||||||
 | 
					static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *suffix_begin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Endpoints on the virtual trunk may have a domain name that is
 | 
				
			||||||
 | 
						 * followed after an @ character, this can be chopped off. All
 | 
				
			||||||
 | 
						 * other supported trunk types do not have any suffixes that may
 | 
				
			||||||
 | 
						 * be chopped off */
 | 
				
			||||||
 | 
						if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
 | 
				
			||||||
 | 
							suffix_begin = strchr(epname, '@');
 | 
				
			||||||
 | 
							if (!suffix_begin)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							*suffix_begin = '\0';
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Convert all characters in epname to lowercase and strip trunk prefix and
 | 
				
			||||||
 | 
					 * endpoint name suffix (domain name) from epname. The result is written to
 | 
				
			||||||
 | 
					 * to the memory pointed at by epname_stripped. The expected size of the
 | 
				
			||||||
 | 
					 * result is either equal or lower then the length of the input string
 | 
				
			||||||
 | 
					 * (epname) */
 | 
				
			||||||
 | 
					static void strip_epname(char *epname_stripped, const char *epname,
 | 
				
			||||||
 | 
								 const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
 | 
				
			||||||
 | 
						chop_epname_prefix(epname_stripped, trunk);
 | 
				
			||||||
 | 
						chop_epname_suffix(epname_stripped, trunk);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Go through the trunk and find a random free (no active calls) endpoint,
 | 
				
			||||||
 | 
					 * this function is called when a wildcarded request is carried out, which
 | 
				
			||||||
 | 
					 * means that it is up to the MGW to choose a random free endpoint. */
 | 
				
			||||||
 | 
					static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
 | 
							endp = trunk->endpoints[i];
 | 
				
			||||||
 | 
							/* A free endpoint must not serve a call already and it must
 | 
				
			||||||
 | 
							 * be available. */
 | 
				
			||||||
 | 
							if (endp->callid == NULL && mgcp_endp_avail(endp))
 | 
				
			||||||
 | 
								return endp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Find an endpoint specified by its name. If the endpoint can not be found,
 | 
				
			||||||
 | 
					 * return NULL */
 | 
				
			||||||
 | 
					static struct mgcp_endpoint *find_specific_endpoint(const char *epname,
 | 
				
			||||||
 | 
											    const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char epname_stripped[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						char epname_stripped_endp[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Strip irrelevant information from the endpoint name */
 | 
				
			||||||
 | 
						strip_epname(epname_stripped, epname, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
 | 
							endp = trunk->endpoints[i];
 | 
				
			||||||
 | 
							strip_epname(epname_stripped_endp, endp->name, trunk);
 | 
				
			||||||
 | 
							if (strcmp(epname_stripped_endp, epname_stripped) == 0)
 | 
				
			||||||
 | 
								return endp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Find an endpoint by its name on a specified trunk.
 | 
				
			||||||
 | 
					 *  \param[out] cause pointer to store cause code, can be NULL.
 | 
				
			||||||
 | 
					 *  \param[in] epname endpoint name to lookup.
 | 
				
			||||||
 | 
					 *  \param[in] trunk where the endpoint is located.
 | 
				
			||||||
 | 
					 *  \returns endpoint or NULL if endpoint was not found. */
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
 | 
				
			||||||
 | 
										      const struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cause)
 | 
				
			||||||
 | 
							*cause = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* At the moment we only support a primitive ('*'-only) method of
 | 
				
			||||||
 | 
						 * wildcarded endpoint searches that picks the next free endpoint on
 | 
				
			||||||
 | 
						 * a trunk. */
 | 
				
			||||||
 | 
						if (strstr(epname, "*")) {
 | 
				
			||||||
 | 
							endp = find_free_endpoint(trunk);
 | 
				
			||||||
 | 
							if (endp) {
 | 
				
			||||||
 | 
								LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
 | 
									 "(trunk:%d) found free endpoint: %s\n",
 | 
				
			||||||
 | 
									 trunk->trunk_nr, endp->name);
 | 
				
			||||||
 | 
								endp->wildcarded_req = true;
 | 
				
			||||||
 | 
								return endp;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "(trunk:%d) Not able to find a free endpoint\n",
 | 
				
			||||||
 | 
							     trunk->trunk_nr);
 | 
				
			||||||
 | 
							if (cause)
 | 
				
			||||||
 | 
								*cause = -403;
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find an endpoint by its name (if wildcarded request is not
 | 
				
			||||||
 | 
						 * applicable) */
 | 
				
			||||||
 | 
						endp = find_specific_endpoint(epname, trunk);
 | 
				
			||||||
 | 
						if (endp) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "(trunk:%d) found endpoint: %s\n",
 | 
				
			||||||
 | 
								 trunk->trunk_nr, endp->name);
 | 
				
			||||||
 | 
							endp->wildcarded_req = false;
 | 
				
			||||||
 | 
							return endp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
						     "(trunk:%d) Not able to find specified endpoint: %s\n",
 | 
				
			||||||
 | 
						     trunk->trunk_nr, epname);
 | 
				
			||||||
 | 
						if (cause)
 | 
				
			||||||
 | 
							*cause = -500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the domain name, which is supplied with the endpoint name
 | 
				
			||||||
 | 
					 * matches the configuration. */
 | 
				
			||||||
 | 
					static int check_domain_name(const char *epname, struct mgcp_config *cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *domain_to_check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						domain_to_check = strstr(epname, "@");
 | 
				
			||||||
 | 
						if (!domain_to_check) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
				
			||||||
 | 
							     epname, cfg->domain);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Accept any domain if configured as "*" */
 | 
				
			||||||
 | 
						if (!strcmp(cfg->domain, "*"))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(domain_to_check+1, cfg->domain) != 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
 | 
				
			||||||
 | 
							     epname, cfg->domain);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Find an endpoint by its name, search at all trunks.
 | 
				
			||||||
 | 
					 *  \param[out] cause, pointer to store cause code, can be NULL.
 | 
				
			||||||
 | 
					 *  \param[in] epname, must contain trunk prefix.
 | 
				
			||||||
 | 
					 *  \param[in] cfg, mgcp configuration (trunks).
 | 
				
			||||||
 | 
					 *  \returns endpoint or NULL if endpoint was not found. */
 | 
				
			||||||
 | 
					struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
 | 
				
			||||||
 | 
										struct mgcp_config *cfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						char epname_lc[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
 | 
				
			||||||
 | 
						epname = epname_lc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cause)
 | 
				
			||||||
 | 
							*cause = -500;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Identify the trunk where the endpoint is located */
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_name(cfg, epname);
 | 
				
			||||||
 | 
						if (!trunk)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* All endpoint names require a domain as suffix */
 | 
				
			||||||
 | 
						if (check_domain_name(epname, cfg))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Identify the endpoint on the trunk */
 | 
				
			||||||
 | 
					        endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
 | 
				
			||||||
 | 
						if (!endp) {
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cause)
 | 
				
			||||||
 | 
							*cause = 0;
 | 
				
			||||||
 | 
						return endp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the E1 timeslot number from a given E1 endpoint name
 | 
				
			||||||
 | 
					 * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
 | 
				
			||||||
 | 
					static uint8_t e1_ts_nr_from_epname(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[MGCP_ENDPOINT_MAXLEN + 1];
 | 
				
			||||||
 | 
						char *save_ptr = NULL;
 | 
				
			||||||
 | 
						char *buf_ptr = buf;
 | 
				
			||||||
 | 
						char *token;
 | 
				
			||||||
 | 
						unsigned long int res = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							token = strtok_r(buf_ptr, "/", &save_ptr);
 | 
				
			||||||
 | 
							buf_ptr = NULL;
 | 
				
			||||||
 | 
							if (!token)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (strncmp(token, "s-", 2) == 0) {
 | 
				
			||||||
 | 
								errno = 0;
 | 
				
			||||||
 | 
								res = strtoul(token + 2, NULL, 10);
 | 
				
			||||||
 | 
								if (errno == ERANGE || res > NUM_E1_TS)
 | 
				
			||||||
 | 
									return 0xff;
 | 
				
			||||||
 | 
								return (uint8_t) res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0xff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the E1 timeslot number from a given E1 endpoint name
 | 
				
			||||||
 | 
					 * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
 | 
				
			||||||
 | 
					static uint8_t e1_rate_from_epname(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[MGCP_ENDPOINT_MAXLEN + 1];
 | 
				
			||||||
 | 
						char *save_ptr = NULL;
 | 
				
			||||||
 | 
						char *buf_ptr = buf;
 | 
				
			||||||
 | 
						char *token;
 | 
				
			||||||
 | 
						unsigned long int res = 0;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							token = strtok_r(buf_ptr, "/", &save_ptr);
 | 
				
			||||||
 | 
							buf_ptr = NULL;
 | 
				
			||||||
 | 
							if (!token)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (strncmp(token, "su", 2) == 0) {
 | 
				
			||||||
 | 
								errno = 0;
 | 
				
			||||||
 | 
								res = strtoul(token + 2, NULL, 10);
 | 
				
			||||||
 | 
								if (errno == ERANGE || res > E1_RATE_MAX)
 | 
				
			||||||
 | 
									return 0xff;
 | 
				
			||||||
 | 
								/* Make sure the rate is a valid rate */
 | 
				
			||||||
 | 
								for (i = 0; i < sizeof(e1_rates); i++) {
 | 
				
			||||||
 | 
									if (res == e1_rates[i])
 | 
				
			||||||
 | 
										return (uint8_t) res;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0xff;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0xff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the E1 bitstream offset from a given E1 endpoint name
 | 
				
			||||||
 | 
					 * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
 | 
				
			||||||
 | 
					static uint8_t e1_offs_from_epname(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buf[MGCP_ENDPOINT_MAXLEN + 1];
 | 
				
			||||||
 | 
						char *save_ptr = NULL;
 | 
				
			||||||
 | 
						char *buf_ptr = buf;
 | 
				
			||||||
 | 
						char *token;
 | 
				
			||||||
 | 
						unsigned long int res = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							token = strtok_r(buf_ptr, "/", &save_ptr);
 | 
				
			||||||
 | 
							buf_ptr = NULL;
 | 
				
			||||||
 | 
							if (!token)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (strncmp(token, "su", 2) == 0) {
 | 
				
			||||||
 | 
								token = strstr(token, "-");
 | 
				
			||||||
 | 
								if (!token)
 | 
				
			||||||
 | 
									return 0xff;
 | 
				
			||||||
 | 
								token += 1;
 | 
				
			||||||
 | 
								errno = 0;
 | 
				
			||||||
 | 
								res = strtoul(token, NULL, 10);
 | 
				
			||||||
 | 
								if (errno == ERANGE || res > E1_OFFS_MAX)
 | 
				
			||||||
 | 
									return 0xff;
 | 
				
			||||||
 | 
								return (uint8_t) res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0xff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get the E1 subslot number (internal) from a given E1 endpoint name
 | 
				
			||||||
 | 
					 * (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
 | 
				
			||||||
 | 
					static uint8_t e1_ss_nr_from_epname(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t rate;
 | 
				
			||||||
 | 
						uint8_t offs;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rate = e1_rate_from_epname(epname);
 | 
				
			||||||
 | 
						offs = e1_offs_from_epname(epname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_static_assert(sizeof(e1_rates) == sizeof(e1_offsets), e1_rates_e1_offsets_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sizeof(e1_rates); i++) {
 | 
				
			||||||
 | 
							if ((e1_rates[i] == rate) && (e1_offsets[i] == offs))
 | 
				
			||||||
 | 
								return i;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0xff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* The following map shows the overlapping of the subslots and their
 | 
				
			||||||
 | 
						 * respective rates. The numbers on the right running from top to bottom
 | 
				
			||||||
 | 
						 * are the bit offsets in the whole 64k timeslot. The numbers inside the
 | 
				
			||||||
 | 
						 * boxes symbolize the internal subslot number (array index) and the
 | 
				
			||||||
 | 
						 * rate in the form: i:r where i is the subslot number and r the
 | 
				
			||||||
 | 
						 * respective rate.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * +--------+--------+--------+--------+ 0
 | 
				
			||||||
 | 
						 * |        |        |        |  7:8k  |
 | 
				
			||||||
 | 
						 * |        |        + 3:16k  +--------+ 1
 | 
				
			||||||
 | 
						 * |        |        |        |  8:8k  |
 | 
				
			||||||
 | 
						 * |        | 1:32k  +--------+--------+ 2
 | 
				
			||||||
 | 
						 * |        |        |        |  9:8k  |
 | 
				
			||||||
 | 
						 * |        |        + 4:16k  +--------+ 3
 | 
				
			||||||
 | 
						 * |        |        |        | 10:8k  |
 | 
				
			||||||
 | 
						 * | 0:64k  +--------+--------+--------+ 4
 | 
				
			||||||
 | 
						 * |        |        |        | 11:8k  |
 | 
				
			||||||
 | 
						 * |        |        + 5:16k  +--------+ 5
 | 
				
			||||||
 | 
						 * |        |        |        | 12:8k  |
 | 
				
			||||||
 | 
						 * |        | 2:32k  +--------+--------+ 6
 | 
				
			||||||
 | 
						 * |        |        |        | 13:8k  |
 | 
				
			||||||
 | 
						 * |        |        + 6:16k  +--------+ 7
 | 
				
			||||||
 | 
						 * |        |        |        | 14:8k  |
 | 
				
			||||||
 | 
						 * +--------+--------+--------+--------+ 8
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * The following array contains tables with the subslot numbers that must be
 | 
				
			||||||
 | 
						 * unused for each subslot. During this test we do not have to check the
 | 
				
			||||||
 | 
						 * endpoint we need to verify, only the overlaps need to be checked. This is
 | 
				
			||||||
 | 
						 * also the reason why the related subslot number is missing from each each
 | 
				
			||||||
 | 
						 * line. */
 | 
				
			||||||
 | 
						const int8_t interlock_tab[MGCP_ENDP_E1_SUBSLOTS][15] = {
 | 
				
			||||||
 | 
							{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1 },
 | 
				
			||||||
 | 
							{ 0, 3, 4, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 5, 6, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 | 
				
			||||||
 | 
							{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const int8_t *interlock;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						uint8_t ts_nr = 0;
 | 
				
			||||||
 | 
						uint8_t ss_nr = 0;
 | 
				
			||||||
 | 
						char *epname_check;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp_check;
 | 
				
			||||||
 | 
						bool available = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This function must only be used with E1 type endpoints! */
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->trunk->trunk_type == MGCP_TRUNK_E1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts_nr = e1_ts_nr_from_epname(endp->name);
 | 
				
			||||||
 | 
						ss_nr = e1_ss_nr_from_epname(endp->name);
 | 
				
			||||||
 | 
						if (ts_nr == 0xff || ss_nr == 0xff) {
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "cannot check endpoint availability, endpoint name not parseable!\n");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						interlock = interlock_tab[ss_nr];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sizeof(interlock_tab[0]); i++) {
 | 
				
			||||||
 | 
							/* Detect row end */
 | 
				
			||||||
 | 
							if (interlock[i] == -1)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Pick overlapping endpoint to check */
 | 
				
			||||||
 | 
							epname_check = gen_e1_epname(endp, endp->trunk->cfg->domain,
 | 
				
			||||||
 | 
										     endp->trunk->trunk_nr, ts_nr,
 | 
				
			||||||
 | 
										     interlock[i]);
 | 
				
			||||||
 | 
							endp_check = find_specific_endpoint(epname_check, endp->trunk);
 | 
				
			||||||
 | 
							if (!endp_check) {
 | 
				
			||||||
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									 "cannot check endpoint availability, overlapping endpoint:%s not found!\n",
 | 
				
			||||||
 | 
									 epname_check);
 | 
				
			||||||
 | 
								talloc_free(epname_check);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							talloc_free(epname_check);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Check if overlapping endpoint currently serves another call
 | 
				
			||||||
 | 
							 * (This is an exceptional situation, that should not occur
 | 
				
			||||||
 | 
							 * in a properly configured environment!) */
 | 
				
			||||||
 | 
							if (endp_check->callid) {
 | 
				
			||||||
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									 "endpoint unavailable - overlapping endpoint:%s already serves a call!\n",
 | 
				
			||||||
 | 
									 endp_check->name);
 | 
				
			||||||
 | 
								available = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return available;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! 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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							/* There are no obstacles that may render a virtual trunk
 | 
				
			||||||
 | 
							 * endpoint unusable, so virtual trunk endpoints are always
 | 
				
			||||||
 | 
							 * available */
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							return endp_avail_e1(endp);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! claim endpoint, sets callid and activates endpoint, should be called at the
 | 
				
			||||||
 | 
					 *  beginning of the CRCX procedure when it is clear that a new call should be
 | 
				
			||||||
 | 
					 *  created.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to claim.
 | 
				
			||||||
 | 
					 *  \param[in] callid that is assingned to this endpoint. */
 | 
				
			||||||
 | 
					int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						uint8_t ts;
 | 
				
			||||||
 | 
						uint8_t ss;
 | 
				
			||||||
 | 
						uint8_t offs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: Make this function more intelligent, it should run the
 | 
				
			||||||
 | 
						 * call id checks we currently have in protocol.c directly here. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set the callid, creation of another connection will only be possible
 | 
				
			||||||
 | 
						 * when the callid matches up. (Connections are distinguished by their
 | 
				
			||||||
 | 
						 * connection ids) */
 | 
				
			||||||
 | 
						endp->callid = talloc_strdup(endp, callid);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp->callid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Allocate resources */
 | 
				
			||||||
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							/* No additional initaliziation required here, virtual
 | 
				
			||||||
 | 
							 * endpoints will open/close network sockets themselves
 | 
				
			||||||
 | 
							 * on demand. */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							ts = e1_ts_nr_from_epname(endp->name);
 | 
				
			||||||
 | 
							ss = e1_ss_nr_from_epname(endp->name);
 | 
				
			||||||
 | 
							offs = e1_offs_from_epname(endp->name);
 | 
				
			||||||
 | 
							OSMO_ASSERT(ts != 0xFF);
 | 
				
			||||||
 | 
							OSMO_ASSERT(ts != 0);
 | 
				
			||||||
 | 
							OSMO_ASSERT(ss != 0xFF);
 | 
				
			||||||
 | 
							OSMO_ASSERT(offs != 0xFF);
 | 
				
			||||||
 | 
							rc = mgcp_e1_endp_equip(endp, ts, ss, offs);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure the endpoint is released when claiming the endpoint fails. */
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! update endpoint, updates internal endpoint specific data, should be
 | 
				
			||||||
 | 
					 *  after when MDCX or CRCX has been executed successuflly.
 | 
				
			||||||
 | 
					 *  \param[in] endp endpoint to update. */
 | 
				
			||||||
 | 
					void mgcp_endp_update(struct mgcp_endpoint *endp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Allocate resources */
 | 
				
			||||||
 | 
						switch (endp->trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							/* No updating initaliziation required for virtual endpoints. */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							mgcp_e1_endp_update(endp);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_add(&conn->entry, &endp->conns);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Run endpoint cleanup action. By this we inform the endpoint about
 | 
				
			||||||
 | 
						 * the removal of the connection and allow it to clean up its inner
 | 
				
			||||||
 | 
						 * state accordingly */
 | 
				
			||||||
 | 
						if (endp->type->cleanup_cb)
 | 
				
			||||||
 | 
							endp->type->cleanup_cb(endp, conn);
 | 
				
			||||||
 | 
						llist_del(&conn->entry);
 | 
				
			||||||
 | 
						if (llist_empty(&endp->conns))
 | 
				
			||||||
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
@@ -105,7 +107,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
		ret = -1;
 | 
							ret = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Special handling für RTP connections */
 | 
						/* Special handling for RTP connections */
 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		conn->u.rtp.end.output_enabled =
 | 
							conn->u.rtp.end.output_enabled =
 | 
				
			||||||
		    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
							    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
				
			||||||
@@ -129,166 +131,6 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* We have a null terminated string with the endpoint name here. We only
 | 
					 | 
				
			||||||
 * support two kinds. Simple ones as seen on the BSC level and the ones
 | 
					 | 
				
			||||||
 * seen on the trunk side. (helper function for find_endpoint()) */
 | 
					 | 
				
			||||||
static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
 | 
					 | 
				
			||||||
					      const char *mgcp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *rest = NULL;
 | 
					 | 
				
			||||||
	struct mgcp_trunk_config *tcfg;
 | 
					 | 
				
			||||||
	int trunk, endp;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp_ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	trunk = strtoul(mgcp + 6, &rest, 10);
 | 
					 | 
				
			||||||
	if (rest == NULL || rest[0] != '/' || trunk < 1) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endp = strtoul(rest + 1, &rest, 10);
 | 
					 | 
				
			||||||
	if (rest == NULL || rest[0] != '@') {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* signalling is on timeslot 1 */
 | 
					 | 
				
			||||||
	if (endp == 1)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tcfg = mgcp_trunk_num(cfg, trunk);
 | 
					 | 
				
			||||||
	if (!tcfg) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n",
 | 
					 | 
				
			||||||
		     trunk);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!tcfg->endpoints) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
		     "Endpoints of trunk %d not allocated.\n", trunk);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (endp < 1 || endp >= tcfg->number_endpoints) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n",
 | 
					 | 
				
			||||||
		     mgcp);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endp_ptr = &tcfg->endpoints[endp];
 | 
					 | 
				
			||||||
	endp_ptr->wildcarded_req = false;
 | 
					 | 
				
			||||||
	return endp_ptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Find an endpoint that is not in use. Do this by going through the endpoint
 | 
					 | 
				
			||||||
 * array, check the callid. A callid nullpointer indicates that the endpoint
 | 
					 | 
				
			||||||
 * is free */
 | 
					 | 
				
			||||||
static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
 | 
					 | 
				
			||||||
						unsigned int number_endpoints)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < number_endpoints; i++) {
 | 
					 | 
				
			||||||
		if (endpoints[i].callid == NULL) {
 | 
					 | 
				
			||||||
			endp = &endpoints[i];
 | 
					 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
			     "found free endpoint\n");
 | 
					 | 
				
			||||||
			endp->wildcarded_req = true;
 | 
					 | 
				
			||||||
			return endp;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "Not able to find a free endpoint\n");
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if the domain name, which is supplied with the endpoint name
 | 
					 | 
				
			||||||
 * matches the configuration. */
 | 
					 | 
				
			||||||
static int check_domain_name(struct mgcp_config *cfg, const char *mgcp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *domain_to_check;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	domain_to_check = strstr(mgcp, "@");
 | 
					 | 
				
			||||||
	if (!domain_to_check)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Accept any domain if configured as "*" */
 | 
					 | 
				
			||||||
	if (!strcmp(cfg->domain, "*"))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strcmp(domain_to_check+1, cfg->domain) != 0) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Wrong domain name '%s', expecting '%s'\n", mgcp, cfg->domain);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Search the endpoint pool for the endpoint that had been selected via the
 | 
					 | 
				
			||||||
 * MGCP message (helper function for mgcp_analyze_header()) */
 | 
					 | 
				
			||||||
static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg,
 | 
					 | 
				
			||||||
					   const char *mgcp,
 | 
					 | 
				
			||||||
					   int *cause)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	char *endptr = NULL;
 | 
					 | 
				
			||||||
	unsigned int gw = INT_MAX;
 | 
					 | 
				
			||||||
	const char *endpoint_number_str;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*cause = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check if the domainname in the request is correct */
 | 
					 | 
				
			||||||
	if (check_domain_name(cfg, mgcp)) {
 | 
					 | 
				
			||||||
		*cause = -500;
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check if the E1 trunk is requested */
 | 
					 | 
				
			||||||
	if (strncmp(mgcp, "ds/e1", 5) == 0) {
 | 
					 | 
				
			||||||
		endp = find_e1_endpoint(cfg, mgcp);
 | 
					 | 
				
			||||||
		if (!endp)
 | 
					 | 
				
			||||||
			*cause = -500;
 | 
					 | 
				
			||||||
		return endp;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check if the virtual trunk is addressed (new, correct way with prefix) */
 | 
					 | 
				
			||||||
	if (strncmp
 | 
					 | 
				
			||||||
	    (mgcp, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
 | 
					 | 
				
			||||||
	     strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK)) == 0) {
 | 
					 | 
				
			||||||
		endpoint_number_str =
 | 
					 | 
				
			||||||
		    mgcp + strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
 | 
					 | 
				
			||||||
		if (endpoint_number_str[0] == '*') {
 | 
					 | 
				
			||||||
			endp = find_free_endpoint(cfg->trunk.endpoints,
 | 
					 | 
				
			||||||
						  cfg->trunk.number_endpoints);
 | 
					 | 
				
			||||||
			if (!endp)
 | 
					 | 
				
			||||||
				*cause = -403;
 | 
					 | 
				
			||||||
			return endp;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		gw = strtoul(endpoint_number_str, &endptr, 16);
 | 
					 | 
				
			||||||
		if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
 | 
					 | 
				
			||||||
			endp = &cfg->trunk.endpoints[gw];
 | 
					 | 
				
			||||||
			endp->wildcarded_req = false;
 | 
					 | 
				
			||||||
			return endp;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Deprecated method without prefix */
 | 
					 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
					 | 
				
			||||||
	     "Addressing virtual trunk without prefix (deprecated), please use %s: '%s'\n",
 | 
					 | 
				
			||||||
	     MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, mgcp);
 | 
					 | 
				
			||||||
	gw = strtoul(mgcp, &endptr, 16);
 | 
					 | 
				
			||||||
	if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
 | 
					 | 
				
			||||||
		endp = &cfg->trunk.endpoints[gw];
 | 
					 | 
				
			||||||
		endp->wildcarded_req = false;
 | 
					 | 
				
			||||||
		return endp;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
 | 
					 | 
				
			||||||
	*cause = -500;
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
					/*! Analyze and parse the the hader of an MGCP messeage string.
 | 
				
			||||||
 *  \param[out] pdata caller provided memory to store the parsing results
 | 
					 *  \param[out] pdata caller provided memory to store the parsing results
 | 
				
			||||||
 *  \param[in] data mgcp message string
 | 
					 *  \param[in] data mgcp message string
 | 
				
			||||||
@@ -316,7 +158,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
			pdata->trans = elem;
 | 
								pdata->trans = elem;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 1:
 | 
							case 1:
 | 
				
			||||||
			pdata->endp = find_endpoint(pdata->cfg, elem, &cause);
 | 
								pdata->endp = mgcp_endp_by_name(&cause, elem, pdata->cfg);
 | 
				
			||||||
			if (!pdata->endp) {
 | 
								if (!pdata->endp) {
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
									LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				     "Unable to find Endpoint `%s'\n", elem);
 | 
									     "Unable to find Endpoint `%s'\n", elem);
 | 
				
			||||||
@@ -390,8 +232,8 @@ int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
 | 
				
			|||||||
	const size_t line_len = strlen(line);
 | 
						const size_t line_len = strlen(line);
 | 
				
			||||||
	if (line[0] != '\0' && line_len < 2) {
 | 
						if (line[0] != '\0' && line_len < 2) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "Wrong MGCP option format: '%s' on 0x%x\n",
 | 
							     "Wrong MGCP option format: '%s' on %s\n",
 | 
				
			||||||
		     line, ENDPOINT_NUMBER(endp));
 | 
							     line, endp->name);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -403,7 +245,7 @@ int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
 | 
				
			|||||||
/*! Check if the specified callid seems plausible.
 | 
					/*! Check if the specified callid seems plausible.
 | 
				
			||||||
  * \param[in] endp pointer to endpoint
 | 
					  * \param[in] endp pointer to endpoint
 | 
				
			||||||
  * \param{in] callid to verify
 | 
					  * \param{in] callid to verify
 | 
				
			||||||
  * \returns 1 when callid seems plausible, 0 on error */
 | 
					  * \returns 0 when callid seems plausible, -1 on error */
 | 
				
			||||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
 | 
					int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*! This function compares the supplied callid with the called that is
 | 
						/*! This function compares the supplied callid with the called that is
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -23,10 +23,11 @@
 | 
				
			|||||||
#include <osmocom/netif/amr.h>
 | 
					#include <osmocom/netif/amr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct osmo_fd osmux_fd;
 | 
					static struct osmo_fd osmux_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,6 +35,7 @@ static LLIST_HEAD(osmux_handle_list);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct osmux_handle {
 | 
					struct osmux_handle {
 | 
				
			||||||
	struct llist_head head;
 | 
						struct llist_head head;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn;
 | 
				
			||||||
	struct osmux_in_handle *in;
 | 
						struct osmux_in_handle *in;
 | 
				
			||||||
	struct in_addr rem_addr;
 | 
						struct in_addr rem_addr;
 | 
				
			||||||
	int rem_port; /* network byte order */
 | 
						int rem_port; /* network byte order */
 | 
				
			||||||
@@ -46,14 +48,17 @@ static void *osmux;
 | 
				
			|||||||
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
 | 
					static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmux_handle *handle = data;
 | 
						struct osmux_handle *handle = data;
 | 
				
			||||||
	struct sockaddr_in out = {
 | 
						struct mgcp_conn_rtp *conn = handle->conn;
 | 
				
			||||||
		.sin_family = AF_INET,
 | 
					 | 
				
			||||||
		.sin_port = handle->rem_port,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
 | 
						if (conn->end.output_enabled) {
 | 
				
			||||||
	sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
 | 
							struct sockaddr_in out = {
 | 
				
			||||||
		(struct sockaddr *)&out, sizeof(out));
 | 
								.sin_family = AF_INET,
 | 
				
			||||||
 | 
								.sin_port = handle->rem_port,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
 | 
				
			||||||
 | 
							sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
 | 
				
			||||||
 | 
								(struct sockaddr *)&out, sizeof(out));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	msgb_free(batch_msg);
 | 
						msgb_free(batch_msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -108,13 +113,15 @@ static void osmux_handle_put(struct osmux_in_handle *in)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Allocate free OSMUX handle */
 | 
					/* Allocate free OSMUX handle */
 | 
				
			||||||
static struct osmux_handle *
 | 
					static struct osmux_handle *
 | 
				
			||||||
osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
 | 
					osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmux_handle *h;
 | 
						struct osmux_handle *h;
 | 
				
			||||||
 | 
						struct mgcp_config *cfg = conn->conn->endp->cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	h = talloc_zero(osmux, struct osmux_handle);
 | 
						h = talloc_zero(osmux, struct osmux_handle);
 | 
				
			||||||
	if (!h)
 | 
						if (!h)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
						h->conn = conn;
 | 
				
			||||||
	h->rem_addr = *addr;
 | 
						h->rem_addr = *addr;
 | 
				
			||||||
	h->rem_port = rem_port;
 | 
						h->rem_port = rem_port;
 | 
				
			||||||
	h->refcnt++;
 | 
						h->refcnt++;
 | 
				
			||||||
@@ -147,15 +154,20 @@ osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
 | 
				
			|||||||
/* Lookup existing handle for a specified address, if the handle can not be
 | 
					/* Lookup existing handle for a specified address, if the handle can not be
 | 
				
			||||||
 * found, the function will automatically allocate one */
 | 
					 * found, the function will automatically allocate one */
 | 
				
			||||||
static struct osmux_in_handle *
 | 
					static struct osmux_in_handle *
 | 
				
			||||||
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
 | 
					osmux_handle_lookup(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *addr, int rem_port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmux_handle *h;
 | 
						struct osmux_handle *h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	h = osmux_handle_find_get(addr, rem_port);
 | 
						if (addr->u.sa.sa_family != AF_INET) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h = osmux_handle_find_get(&addr->u.sin.sin_addr, rem_port);
 | 
				
			||||||
	if (h != NULL)
 | 
						if (h != NULL)
 | 
				
			||||||
		return h->in;
 | 
							return h->in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	h = osmux_handle_alloc(cfg, addr, rem_port);
 | 
						h = osmux_handle_alloc(conn, &addr->u.sin.sin_addr, rem_port);
 | 
				
			||||||
	if (h == NULL)
 | 
						if (h == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,14 +209,15 @@ static struct mgcp_conn_rtp*
 | 
				
			|||||||
osmux_conn_lookup(struct mgcp_config *cfg, uint8_t cid,
 | 
					osmux_conn_lookup(struct mgcp_config *cfg, uint8_t cid,
 | 
				
			||||||
		struct in_addr *from_addr)
 | 
							struct in_addr *from_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	struct mgcp_conn *conn = NULL;
 | 
						struct mgcp_conn *conn = NULL;
 | 
				
			||||||
	struct mgcp_conn_rtp * conn_rtp;
 | 
						struct mgcp_conn_rtp * conn_rtp;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i=0; i<cfg->trunk.number_endpoints; i++) {
 | 
						for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		endp = &cfg->trunk.endpoints[i];
 | 
							endp = trunk->endpoints[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		llist_for_each_entry(conn, &endp->conns, entry) {
 | 
							llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
			if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
								if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
				
			||||||
@@ -234,13 +247,15 @@ static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = data;
 | 
						struct mgcp_conn_rtp *conn = data;
 | 
				
			||||||
	struct mgcp_endpoint *endp = conn->conn->endp;
 | 
						struct mgcp_endpoint *endp = conn->conn->endp;
 | 
				
			||||||
	struct sockaddr_in addr = {
 | 
						struct osmo_sockaddr addr = { /* FIXME: do we know the source address?? */ };
 | 
				
			||||||
		.sin_addr = conn->end.addr,
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
		.sin_port = conn->end.rtp_port,
 | 
						*mc = (struct osmo_rtp_msg_ctx){
 | 
				
			||||||
	}; /* FIXME: not set/used in cb */
 | 
							.proto = MGCP_PROTO_RTP,
 | 
				
			||||||
 | 
							.conn_src = conn,
 | 
				
			||||||
 | 
							.from_addr = &addr,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp->type->dispatch_rtp_cb(msg);
 | 
				
			||||||
	endp->type->dispatch_rtp_cb(MGCP_PROTO_RTP, &addr, (char *)msg->data, msg->len, conn->conn);
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -271,6 +286,8 @@ static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
 | 
				
			|||||||
static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
				  bool sending)
 | 
									  bool sending)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(conn->osmux.state) {
 | 
						switch(conn->osmux.state) {
 | 
				
			||||||
	case OSMUX_STATE_ACTIVATING:
 | 
						case OSMUX_STATE_ACTIVATING:
 | 
				
			||||||
	if (osmux_enable_conn(endp, conn, &conn->end.addr, conn->end.rtp_port) < 0) {
 | 
						if (osmux_enable_conn(endp, conn, &conn->end.addr, conn->end.rtp_port) < 0) {
 | 
				
			||||||
@@ -283,7 +300,8 @@ static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_r
 | 
				
			|||||||
		LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "Osmux %s CID %u towards %s:%u is now enabled\n",
 | 
								 "Osmux %s CID %u towards %s:%u is now enabled\n",
 | 
				
			||||||
			 sending ? "sent" : "received",
 | 
								 sending ? "sent" : "received",
 | 
				
			||||||
			 conn->osmux.cid, inet_ntoa(conn->end.addr),
 | 
								 conn->osmux.cid,
 | 
				
			||||||
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(conn->end.rtp_port));
 | 
								 ntohs(conn->end.rtp_port));
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	case OSMUX_STATE_ENABLED:
 | 
						case OSMUX_STATE_ENABLED:
 | 
				
			||||||
@@ -372,6 +390,8 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			|||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mgcp_conn_watchdog_kick(conn_src->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*conn_dst = mgcp_find_dst_conn(conn_src->conn);
 | 
							/*conn_dst = mgcp_find_dst_conn(conn_src->conn);
 | 
				
			||||||
		if (!conn_dst) {
 | 
							if (!conn_dst) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -396,8 +416,7 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmux_fd.cb = osmux_read_fd_cb;
 | 
						osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, cfg, 0);
 | 
				
			||||||
	osmux_fd.data = cfg;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
 | 
						ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
@@ -406,7 +425,6 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
 | 
						mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
 | 
				
			||||||
	osmux_fd.when |= OSMO_FD_READ;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = osmo_fd_register(&osmux_fd);
 | 
						ret = osmo_fd_register(&osmux_fd);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
@@ -429,7 +447,7 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
 *  \param[in] port portnumber of the remote OSMUX endpoint (in network byte order)
 | 
					 *  \param[in] port portnumber of the remote OSMUX endpoint (in network byte order)
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR */
 | 
					 *  \returns 0 on success, -1 on ERROR */
 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
		      struct in_addr *addr, uint16_t port)
 | 
							      struct osmo_sockaddr *addr, uint16_t port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*! If osmux is enabled, initialize the output handler. This handler is
 | 
						/*! If osmux is enabled, initialize the output handler. This handler is
 | 
				
			||||||
	 *  used to reconstruct the RTP flow from osmux. The RTP SSRC is
 | 
						 *  used to reconstruct the RTP flow from osmux. The RTP SSRC is
 | 
				
			||||||
@@ -440,7 +458,7 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
	 *  overlapping RTP SSRC traveling to the BTSes behind the BSC,
 | 
						 *  overlapping RTP SSRC traveling to the BTSes behind the BSC,
 | 
				
			||||||
	 *  similarly, for flows traveling to the MSC.
 | 
						 *  similarly, for flows traveling to the MSC.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct in_addr addr_unset = {};
 | 
						struct in6_addr addr_unset = {};
 | 
				
			||||||
	static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
						static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
				
			||||||
	uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 | 
						uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -453,13 +471,16 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Wait until we have the connection information from MDCX */
 | 
						/* Wait until we have the connection information from MDCX */
 | 
				
			||||||
	if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0) {
 | 
						if (memcmp(&conn->end.addr, &addr_unset,
 | 
				
			||||||
 | 
							   conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
				
			||||||
 | 
								sizeof(struct in6_addr) :
 | 
				
			||||||
 | 
								sizeof(struct in_addr)) == 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
				
			||||||
			"Osmux remote address/port still unknown\n");
 | 
								"Osmux remote address/port still unknown\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
 | 
						conn->osmux.in = osmux_handle_lookup(conn, addr, port);
 | 
				
			||||||
	if (!conn->osmux.in) {
 | 
						if (!conn->osmux.in) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			"Cannot allocate input osmux handle for conn:%s\n",
 | 
								"Cannot allocate input osmux handle for conn:%s\n",
 | 
				
			||||||
@@ -555,6 +576,7 @@ int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid)
 | 
				
			|||||||
 *  \returns bytes sent, -1 on error */
 | 
					 *  \returns bytes sent, -1 on error */
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	struct osmux_hdr *osmuxh;
 | 
						struct osmux_hdr *osmuxh;
 | 
				
			||||||
	int buf_len;
 | 
						int buf_len;
 | 
				
			||||||
	struct in_addr addr_unset = {};
 | 
						struct in_addr addr_unset = {};
 | 
				
			||||||
@@ -584,7 +606,8 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "sending OSMUX dummy load to %s:%u CID %u\n",
 | 
							 "sending OSMUX dummy load to %s:%u CID %u\n",
 | 
				
			||||||
		 inet_ntoa(conn->end.addr), ntohs(conn->end.rtp_port), conn->osmux.cid);
 | 
							 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
 | 
				
			||||||
 | 
							 ntohs(conn->end.rtp_port), conn->osmux.cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
 | 
						return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
 | 
				
			||||||
			     conn->end.rtp_port, (char*)osmuxh, buf_len);
 | 
								     conn->end.rtp_port, (char*)osmuxh, buf_len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,14 +32,16 @@
 | 
				
			|||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
#include <osmocom/core/select.h>
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
#include <osmocom/core/stats.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_network.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_stat.h>
 | 
					#include <osmocom/mgcp/mgcp_stat.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
@@ -53,101 +55,6 @@ struct mgcp_request {
 | 
				
			|||||||
#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
 | 
					#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
 | 
				
			||||||
	{ .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
 | 
						{ .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
					 | 
				
			||||||
	/* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_MSGS_TOTAL] = {"mgcp:rx_msgs", "total number of MGCP messages received."},
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = {"mgcp:rx_msgs_retransmitted", "number of received retransmissions."},
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_MSGS_HANDLED] = {"mgcp:rx_msgs_handled", "number of handled MGCP messages."},
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_MSGS_UNHANDLED] = {"mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages."},
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_FAIL_MSG_PARSE] = {"mgcp:err_rx_msg_parse", "error parsing MGCP message."},
 | 
					 | 
				
			||||||
	[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] = {"mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints."},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "mgcp",
 | 
					 | 
				
			||||||
	.group_description = "mgcp general statistics",
 | 
					 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = mgcp_general_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
					 | 
				
			||||||
	[MGCP_CRCX_SUCCESS] = {"crcx:success", "CRCX command processed successfully."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_BAD_ACTION] = {"crcx:bad_action", "bad action in CRCX command."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_UNHANDLED_PARAM] = {"crcx:unhandled_param", "unhandled parameter in CRCX command."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_MISSING_CALLID] = {"crcx:missing_callid", "missing CallId in CRCX command."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_INVALID_MODE] = {"crcx:invalid_mode", "invalid connection mode in CRCX command."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = {"crcx:limit_exceeded", "limit of concurrent connections was reached."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_UNKNOWN_CALLID] = {"crcx:unkown_callid", "unknown CallId in CRCX command."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_ALLOC_CONN] = {"crcx:alloc_conn_fail", "connection allocation failure."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] = {"crcx:no_remote_conn_desc", "no opposite end specified for connection."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_START_RTP] = {"crcx:start_rtp_failure", "failure to start RTP processing."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = {"crcx:conn_rejected", "connection rejected by policy."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_NO_OSMUX] = {"crcx:no_osmux", "no osmux offered by peer."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = {"crcx:conn_opt", "connection options invalid."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = {"crcx:codec_nego", "codec negotiation failure."},
 | 
					 | 
				
			||||||
	[MGCP_CRCX_FAIL_BIND_PORT] = {"crcx:bind_port", "port bind failure."},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "crcx",
 | 
					 | 
				
			||||||
	.group_description = "crxc statistics",
 | 
					 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = mgcp_crcx_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
 | 
					 | 
				
			||||||
	[MGCP_MDCX_SUCCESS] = {"mdcx:success", "MDCX command processed successfully."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_WILDCARD] = {"mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_NO_CONN] = {"mdcx:no_conn", "endpoint specified in MDCX command has no active connections."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_INVALID_CALLID] = {"mdcx:callid", "invalid CallId specified in MDCX command."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_INVALID_CONNID] = {"mdcx:connid", "invalid connection ID specified in MDCX command."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_UNHANDLED_PARAM] = {"crcx:unhandled_param", "unhandled parameter in MDCX command."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_NO_CONNID] = {"mdcx:no_connid", "no connection ID specified in MDCX command."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_CONN_NOT_FOUND] = {"mdcx:conn_not_found", "connection specified in MDCX command does not exist."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_INVALID_MODE] = {"mdcx:invalid_mode", "invalid connection mode in MDCX command."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = {"mdcx:conn_opt", "connection options invalid."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] = {"mdcx:no_remote_conn_desc", "no opposite end specified for connection."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_START_RTP] = {"mdcx:start_rtp_failure", "failure to start RTP processing."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = {"mdcx:conn_rejected", "connection rejected by policy."},
 | 
					 | 
				
			||||||
	[MGCP_MDCX_DEFERRED_BY_POLICY] = {"mdcx:conn_deferred", "connection deferred by policy."},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "mdcx",
 | 
					 | 
				
			||||||
	.group_description = "mdcx statistics",
 | 
					 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = mgcp_mdcx_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
					 | 
				
			||||||
	[MGCP_DLCX_SUCCESS] = {"dlcx:success", "DLCX command processed successfully."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_WILDCARD] = {"dlcx:wildcard", "wildcard names in DLCX commands are unsupported."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_NO_CONN] = {"dlcx:no_conn", "endpoint specified in DLCX command has no active connections."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_INVALID_CALLID] = {"dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_INVALID_CONNID] = {"dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = {"dlcx:unhandled_param", "unhandled parameter in DLCX command."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = {"dlcx:rejected", "connection deletion rejected by policy."},
 | 
					 | 
				
			||||||
	[MGCP_DLCX_DEFERRED_BY_POLICY] = {"dlcx:deferred", "connection deletion deferred by policy."},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "dlcx",
 | 
					 | 
				
			||||||
	.group_description = "dlcx statistics",
 | 
					 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = mgcp_dlcx_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "all_rtp_conn",
 | 
					 | 
				
			||||||
	.group_description = "aggregated statistics for all rtp connections",
 | 
					 | 
				
			||||||
	.class_id = 1,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
 | 
					static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *data);
 | 
				
			||||||
static struct msgb *handle_create_con(struct mgcp_parse_data *data);
 | 
					static struct msgb *handle_create_con(struct mgcp_parse_data *data);
 | 
				
			||||||
@@ -254,11 +161,11 @@ static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
 | 
				
			|||||||
	 * Remember the last transmission per endpoint.
 | 
						 * Remember the last transmission per endpoint.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (endp) {
 | 
						if (endp) {
 | 
				
			||||||
		struct mgcp_trunk_config *tcfg = endp->tcfg;
 | 
							struct mgcp_trunk *trunk = endp->trunk;
 | 
				
			||||||
		talloc_free(endp->last_response);
 | 
							talloc_free(endp->last_response);
 | 
				
			||||||
		talloc_free(endp->last_trans);
 | 
							talloc_free(endp->last_trans);
 | 
				
			||||||
		endp->last_trans = talloc_strdup(tcfg->endpoints, trans);
 | 
							endp->last_trans = talloc_strdup(trunk->endpoints, trans);
 | 
				
			||||||
		endp->last_response = talloc_strndup(tcfg->endpoints,
 | 
							endp->last_response = talloc_strndup(trunk->endpoints,
 | 
				
			||||||
						     (const char *)res->l2h,
 | 
											     (const char *)res->l2h,
 | 
				
			||||||
						     msgb_l2len(res));
 | 
											     msgb_l2len(res));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -296,10 +203,8 @@ static int add_params(struct msgb *msg, const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* NOTE: Only in the virtual trunk we allow dynamic endpoint names */
 | 
						/* NOTE: Only in the virtual trunk we allow dynamic endpoint names */
 | 
				
			||||||
	if (endp->wildcarded_req
 | 
						if (endp->wildcarded_req
 | 
				
			||||||
	    && endp->tcfg->trunk_type == MGCP_TRUNK_VIRTUAL) {
 | 
						    && endp->trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
 | 
				
			||||||
		rc = msgb_printf(msg, "Z: %s%x@%s\r\n",
 | 
							rc = msgb_printf(msg, "Z: %s\r\n", endp->name);
 | 
				
			||||||
				 MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
 | 
					 | 
				
			||||||
				 ENDPOINT_NUMBER(endp), endp->cfg->domain);
 | 
					 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -318,24 +223,22 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
					     const char *trans_id,
 | 
										     const char *trans_id,
 | 
				
			||||||
					     bool add_conn_params)
 | 
										     bool add_conn_params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* TODO: we may want to define another local_ip_osmux var to us for
 | 
						/* cfg->local_ip allows overwritting the announced IP address with
 | 
				
			||||||
	   OSMUX connections. Perhaps adding a new internal API to get it based
 | 
						 * regards to the one we actually bind to. Useful in behind-NAT
 | 
				
			||||||
	   on conn type */
 | 
						 * scenarios.
 | 
				
			||||||
	const char *addr = endp->cfg->local_ip;
 | 
						 * TODO: we may want to define another local_ip_osmux var to
 | 
				
			||||||
 | 
						 * us for OSMUX connections. Perhaps adding a new internal API to get it
 | 
				
			||||||
 | 
						 * based on conn type.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const char *addr = endp->cfg->local_ip ? : conn->end.local_addr;
 | 
				
			||||||
	struct msgb *sdp;
 | 
						struct msgb *sdp;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct msgb *result;
 | 
						struct msgb *result;
 | 
				
			||||||
	char local_ip_addr[INET_ADDRSTRLEN];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdp = msgb_alloc_headroom(4096, 128, "sdp record");
 | 
						sdp = msgb_alloc_headroom(4096, 128, "sdp record");
 | 
				
			||||||
	if (!sdp)
 | 
						if (!sdp)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!addr) {
 | 
					 | 
				
			||||||
		mgcp_get_local_addr(local_ip_addr, conn);
 | 
					 | 
				
			||||||
		addr = local_ip_addr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Attach optional connection parameters */
 | 
						/* Attach optional connection parameters */
 | 
				
			||||||
	if (add_conn_params) {
 | 
						if (add_conn_params) {
 | 
				
			||||||
		rc = add_params(sdp, endp, conn);
 | 
							rc = add_params(sdp, endp, conn);
 | 
				
			||||||
@@ -379,8 +282,7 @@ static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 *   - or a response (three numbers, space, transaction id) */
 | 
					 *   - or a response (three numbers, space, transaction id) */
 | 
				
			||||||
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
					struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = &cfg->trunk;
 | 
						struct rate_ctr_group *rate_ctrs = cfg->ratectr.mgcp_general_ctr_group;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = tcfg->mgcp_general_ctr_group;
 | 
					 | 
				
			||||||
	struct mgcp_parse_data pdata;
 | 
						struct mgcp_parse_data pdata;
 | 
				
			||||||
	int rc, i, code, handled = 0;
 | 
						int rc, i, code, handled = 0;
 | 
				
			||||||
	struct msgb *resp = NULL;
 | 
						struct msgb *resp = NULL;
 | 
				
			||||||
@@ -468,13 +370,10 @@ static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
 | 
				
			|||||||
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_rtp_end *end;
 | 
					 | 
				
			||||||
	struct mgcp_port_range *range;
 | 
						struct mgcp_port_range *range;
 | 
				
			||||||
	unsigned int tries;
 | 
						unsigned int tries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	end = &conn->end;
 | 
					 | 
				
			||||||
	OSMO_ASSERT(end);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	range = &endp->cfg->net_ports;
 | 
						range = &endp->cfg->net_ports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -625,6 +524,7 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	char *lco_id;
 | 
						char *lco_id;
 | 
				
			||||||
	char codec[17];
 | 
						char codec[17];
 | 
				
			||||||
 | 
						char nt[17];
 | 
				
			||||||
	int len;
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!options)
 | 
						if (!options)
 | 
				
			||||||
@@ -651,7 +551,7 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
				lco->pkt_period_max = lco->pkt_period_min;
 | 
									lco->pkt_period_max = lco->pkt_period_min;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'a':
 | 
							case 'a':
 | 
				
			||||||
			/* FIXME: LCO also supports the negotiation of more then one codec.
 | 
								/* FIXME: LCO also supports the negotiation of more than one codec.
 | 
				
			||||||
			 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
								 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
				
			||||||
			 * codec only. */
 | 
								 * codec only. */
 | 
				
			||||||
			if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
 | 
								if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
 | 
				
			||||||
@@ -663,6 +563,10 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
				osmo_str_toupper_buf(lco->codec, len + 1, codec);
 | 
									osmo_str_toupper_buf(lco->codec, len + 1, codec);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'n':
 | 
				
			||||||
 | 
								if (lco_id[1] == 't' && sscanf(lco_id + 2, ":%16[^,]", nt) == 1)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/* else: fall throught to print notice log */
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "LCO: unhandled option: '%c'/%d in \"%s\"\n",
 | 
								     "LCO: unhandled option: '%c'/%d in \"%s\"\n",
 | 
				
			||||||
@@ -692,13 +596,13 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
					void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			||||||
			 struct mgcp_rtp_end *rtp)
 | 
								 struct mgcp_rtp_end *rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = endp->tcfg;
 | 
						struct mgcp_trunk *trunk = endp->trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int patch_ssrc = expect_ssrc_change && tcfg->force_constant_ssrc;
 | 
						int patch_ssrc = expect_ssrc_change && trunk->force_constant_ssrc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp->force_aligned_timing = tcfg->force_aligned_timing;
 | 
						rtp->force_aligned_timing = trunk->force_aligned_timing;
 | 
				
			||||||
	rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
 | 
						rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
 | 
				
			||||||
	rtp->rfc5993_hr_convert = tcfg->rfc5993_hr_convert;
 | 
						rtp->rfc5993_hr_convert = trunk->rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "Configuring RTP endpoint: local port %d%s%s\n",
 | 
							 "Configuring RTP endpoint: local port %d%s%s\n",
 | 
				
			||||||
@@ -808,7 +712,7 @@ static bool parse_x_osmo_ign(struct mgcp_endpoint *endp, char *line)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	char *saveptr = NULL;
 | 
						char *saveptr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strncmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
 | 
						if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER)))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	line += strlen(MGCP_X_OSMO_IGN_HEADER);
 | 
						line += strlen(MGCP_X_OSMO_IGN_HEADER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -830,9 +734,9 @@ static bool parse_x_osmo_ign(struct mgcp_endpoint *endp, char *line)
 | 
				
			|||||||
/* CRCX command handler, processes the received command */
 | 
					/* CRCX command handler, processes the received command */
 | 
				
			||||||
static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
					static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = p->endp->tcfg;
 | 
						struct mgcp_trunk *trunk = p->endp->trunk;
 | 
				
			||||||
	struct mgcp_endpoint *endp = p->endp;
 | 
						struct mgcp_endpoint *endp = p->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = tcfg->mgcp_crcx_ctr_group;
 | 
						struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
 | 
				
			||||||
	int error_code = 400;
 | 
						int error_code = 400;
 | 
				
			||||||
	const char *local_options = NULL;
 | 
						const char *local_options = NULL;
 | 
				
			||||||
	const char *callid = NULL;
 | 
						const char *callid = NULL;
 | 
				
			||||||
@@ -846,6 +750,13 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_endp_avail(endp)) {
 | 
				
			||||||
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_AVAIL]);
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "CRCX: selected endpoint not available!\n");
 | 
				
			||||||
 | 
							return create_err_response(NULL, 501, "CRCX", p->trans);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse CallID C: and LocalParameters L: */
 | 
						/* parse CallID C: and LocalParameters L: */
 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
		if (!mgcp_check_param(endp, line))
 | 
							if (!mgcp_check_param(endp, line))
 | 
				
			||||||
@@ -915,7 +826,7 @@ mgcp_header_done:
 | 
				
			|||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			"CRCX: endpoint full, max. %i connections allowed!\n",
 | 
								"CRCX: endpoint full, max. %i connections allowed!\n",
 | 
				
			||||||
			endp->type->max_conns);
 | 
								endp->type->max_conns);
 | 
				
			||||||
		if (tcfg->force_realloc) {
 | 
							if (trunk->force_realloc) {
 | 
				
			||||||
			/* There is no more room for a connection, make some
 | 
								/* There is no more room for a connection, make some
 | 
				
			||||||
			 * room by blindly tossing the oldest of the two two
 | 
								 * room by blindly tossing the oldest of the two two
 | 
				
			||||||
			 * connections */
 | 
								 * connections */
 | 
				
			||||||
@@ -934,7 +845,7 @@ mgcp_header_done:
 | 
				
			|||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: already seized by other call (%s)\n",
 | 
								 "CRCX: already seized by other call (%s)\n",
 | 
				
			||||||
			 endp->callid);
 | 
								 endp->callid);
 | 
				
			||||||
		if (tcfg->force_realloc)
 | 
							if (trunk->force_realloc)
 | 
				
			||||||
			/* This is not our call, toss everything by releasing
 | 
								/* This is not our call, toss everything by releasing
 | 
				
			||||||
			 * the entire endpoint. (rude!) */
 | 
								 * the entire endpoint. (rude!) */
 | 
				
			||||||
			mgcp_endp_release(endp);
 | 
								mgcp_endp_release(endp);
 | 
				
			||||||
@@ -946,13 +857,19 @@ mgcp_header_done:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set the callid, creation of another connection will only be possible
 | 
						if (!endp->callid) {
 | 
				
			||||||
	 * when the callid matches up. (Connections are distinguished by their
 | 
							/* Claim endpoint resources. This will also set the callid,
 | 
				
			||||||
	 * connection ids) */
 | 
							 * creating additional connections will only be possible if
 | 
				
			||||||
	endp->callid = talloc_strdup(tcfg->endpoints, callid);
 | 
							 * the callid matches up (see above). */
 | 
				
			||||||
 | 
							rc = mgcp_endp_claim(endp, callid);
 | 
				
			||||||
 | 
							if (rc != 0) {
 | 
				
			||||||
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_CLAIM]);
 | 
				
			||||||
 | 
								return create_err_response(endp, 502, "CRCX", p->trans);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(conn_name, sizeof(conn_name), "%s", callid);
 | 
						snprintf(conn_name, sizeof(conn_name), "%s", callid);
 | 
				
			||||||
	_conn = mgcp_conn_alloc(tcfg->endpoints, endp, MGCP_CONN_TYPE_RTP, conn_name);
 | 
						_conn = mgcp_conn_alloc(trunk->endpoints, endp, MGCP_CONN_TYPE_RTP, conn_name);
 | 
				
			||||||
	if (!_conn) {
 | 
						if (!_conn) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: unable to allocate RTP connection\n");
 | 
								 "CRCX: unable to allocate RTP connection\n");
 | 
				
			||||||
@@ -960,6 +877,7 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, _conn->id);
 | 
						conn = mgcp_conn_get_rtp(endp, _conn->id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -987,7 +905,7 @@ mgcp_header_done:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Set local connection options, if present */
 | 
						/* Set local connection options, if present */
 | 
				
			||||||
	if (local_options) {
 | 
						if (local_options) {
 | 
				
			||||||
		rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
							rc = set_local_cx_options(endp->trunk->endpoints,
 | 
				
			||||||
					  &endp->local_options, local_options);
 | 
										  &endp->local_options, local_options);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1007,8 +925,8 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->end.fmtp_extra = talloc_strdup(tcfg->endpoints,
 | 
						conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
 | 
				
			||||||
					     tcfg->audio_fmtp_extra);
 | 
										     trunk->audio_fmtp_extra);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->cfg->force_ptime) {
 | 
						if (p->cfg->force_ptime) {
 | 
				
			||||||
		conn->end.packet_duration_ms = p->cfg->force_ptime;
 | 
							conn->end.packet_duration_ms = p->cfg->force_ptime;
 | 
				
			||||||
@@ -1028,6 +946,9 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find a local address for conn based on policy and initial SDP remote
 | 
				
			||||||
 | 
						   information, then find a free port for it */
 | 
				
			||||||
 | 
						mgcp_get_local_addr(conn->end.local_addr, conn);
 | 
				
			||||||
	if (allocate_port(endp, conn) != 0) {
 | 
						if (allocate_port(endp, conn) != 0) {
 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_BIND_PORT]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_BIND_PORT]);
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
@@ -1043,8 +964,7 @@ mgcp_header_done:
 | 
				
			|||||||
	/* policy CB */
 | 
						/* policy CB */
 | 
				
			||||||
	if (p->cfg->policy_cb) {
 | 
						if (p->cfg->policy_cb) {
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
		rc = p->cfg->policy_cb(tcfg, ENDPOINT_NUMBER(endp),
 | 
							rc = p->cfg->policy_cb(endp, MGCP_ENDP_CRCX, p->trans);
 | 
				
			||||||
				       MGCP_ENDP_CRCX, p->trans);
 | 
					 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
								LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
@@ -1066,17 +986,18 @@ mgcp_header_done:
 | 
				
			|||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "CRCX: Creating connection: port: %u\n", conn->end.local_port);
 | 
							 "CRCX: Creating connection: port: %u\n", conn->end.local_port);
 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
		p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
 | 
							p->cfg->change_cb(endp, MGCP_ENDP_CRCX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(tcfg->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
						OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
	if (conn->conn->mode & MGCP_CONN_RECV_ONLY
 | 
						if (conn->conn->mode & MGCP_CONN_RECV_ONLY
 | 
				
			||||||
	    && tcfg->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    && trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		 "CRCX: connection successfully created\n");
 | 
							 "CRCX: connection successfully created\n");
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]);
 | 
						rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]);
 | 
				
			||||||
 | 
						mgcp_endp_update(endp);
 | 
				
			||||||
	return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
 | 
						return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
 | 
				
			||||||
error2:
 | 
					error2:
 | 
				
			||||||
	mgcp_endp_release(endp);
 | 
						mgcp_endp_release(endp);
 | 
				
			||||||
@@ -1085,16 +1006,12 @@ error2:
 | 
				
			|||||||
	return create_err_response(endp, error_code, "CRCX", p->trans);
 | 
						return create_err_response(endp, error_code, "CRCX", p->trans);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* MDCX command handler, processes the received command */
 | 
					/* MDCX command handler, processes the received command */
 | 
				
			||||||
static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
					static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = p->endp->tcfg;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp = p->endp;
 | 
						struct mgcp_endpoint *endp = p->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = tcfg->mgcp_mdcx_ctr_group;
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.mgcp_mdcx_ctr_group;
 | 
				
			||||||
 | 
						char new_local_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int error_code = 500;
 | 
						int error_code = 500;
 | 
				
			||||||
	int silent = 0;
 | 
						int silent = 0;
 | 
				
			||||||
	int have_sdp = 0;
 | 
						int have_sdp = 0;
 | 
				
			||||||
@@ -1108,6 +1025,13 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_endp_avail(endp)) {
 | 
				
			||||||
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_AVAIL]);
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "MDCX: selected endpoint not available!\n");
 | 
				
			||||||
 | 
							return create_err_response(NULL, 501, "MDCX", p->trans);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (endp->wildcarded_req) {
 | 
						if (endp->wildcarded_req) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1202,7 +1126,7 @@ mgcp_header_done:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Set local connection options, if present */
 | 
						/* Set local connection options, if present */
 | 
				
			||||||
	if (local_options) {
 | 
						if (local_options) {
 | 
				
			||||||
		rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
							rc = set_local_cx_options(endp->trunk->endpoints,
 | 
				
			||||||
					  &endp->local_options, local_options);
 | 
										  &endp->local_options, local_options);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1252,6 +1176,20 @@ mgcp_header_done:
 | 
				
			|||||||
		   that conn. */
 | 
							   that conn. */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* MDCX may have provided a new remote address, which means we may need
 | 
				
			||||||
 | 
						   to update our announced IP addr and re-bind our local end. This can
 | 
				
			||||||
 | 
						   happen for instance if MGW initially provided an IPv4 during CRCX
 | 
				
			||||||
 | 
						   ACK, and now MDCX tells us the remote has an IPv6 address. */
 | 
				
			||||||
 | 
						mgcp_get_local_addr(new_local_addr, conn);
 | 
				
			||||||
 | 
						if (strcmp(new_local_addr, conn->end.local_addr)) {
 | 
				
			||||||
 | 
							osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 | 
				
			||||||
 | 
							mgcp_free_rtp_port(&conn->end);
 | 
				
			||||||
 | 
							if (allocate_port(endp, conn) != 0) {
 | 
				
			||||||
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_BIND_PORT]);
 | 
				
			||||||
 | 
								goto error3;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (setup_rtp_processing(endp, conn) != 0) {
 | 
						if (setup_rtp_processing(endp, conn) != 0) {
 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_START_RTP]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_START_RTP]);
 | 
				
			||||||
		goto error3;
 | 
							goto error3;
 | 
				
			||||||
@@ -1261,8 +1199,7 @@ mgcp_header_done:
 | 
				
			|||||||
	/* policy CB */
 | 
						/* policy CB */
 | 
				
			||||||
	if (p->cfg->policy_cb) {
 | 
						if (p->cfg->policy_cb) {
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
		rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
							rc = p->cfg->policy_cb(endp, MGCP_ENDP_MDCX, p->trans);
 | 
				
			||||||
				       MGCP_ENDP_MDCX, p->trans);
 | 
					 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
@@ -1291,13 +1228,12 @@ mgcp_header_done:
 | 
				
			|||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "MDCX: modified conn:%s\n", mgcp_conn_dump(conn->conn));
 | 
							 "MDCX: modified conn:%s\n", mgcp_conn_dump(conn->conn));
 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
							p->cfg->change_cb(endp, MGCP_ENDP_MDCX);
 | 
				
			||||||
				  MGCP_ENDP_MDCX);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(endp->tcfg->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
						OSMO_ASSERT(endp->trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
	if (conn->conn->mode & MGCP_CONN_RECV_ONLY
 | 
						if (conn->conn->mode & MGCP_CONN_RECV_ONLY
 | 
				
			||||||
	    && endp->tcfg->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    && endp->trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_SUCCESS]);
 | 
						rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_SUCCESS]);
 | 
				
			||||||
@@ -1306,6 +1242,7 @@ mgcp_header_done:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		 "MDCX: connection successfully modified\n");
 | 
							 "MDCX: connection successfully modified\n");
 | 
				
			||||||
 | 
						mgcp_endp_update(endp);
 | 
				
			||||||
	return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
 | 
						return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
 | 
				
			||||||
error3:
 | 
					error3:
 | 
				
			||||||
	return create_err_response(endp, error_code, "MDCX", p->trans);
 | 
						return create_err_response(endp, error_code, "MDCX", p->trans);
 | 
				
			||||||
@@ -1318,9 +1255,8 @@ out_silent:
 | 
				
			|||||||
/* DLCX command handler, processes the received command */
 | 
					/* DLCX command handler, processes the received command */
 | 
				
			||||||
static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
					static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = p->endp->tcfg;
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp = p->endp;
 | 
						struct mgcp_endpoint *endp = p->endp;
 | 
				
			||||||
	struct rate_ctr_group *rate_ctrs = tcfg->mgcp_dlcx_ctr_group;
 | 
						struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.mgcp_dlcx_ctr_group;
 | 
				
			||||||
	int error_code = 400;
 | 
						int error_code = 400;
 | 
				
			||||||
	int silent = 0;
 | 
						int silent = 0;
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
@@ -1331,6 +1267,13 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		 "DLCX: deleting connection ...\n");
 | 
							 "DLCX: deleting connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_endp_avail(endp)) {
 | 
				
			||||||
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_AVAIL]);
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "DLCX: selected endpoint not available!\n");
 | 
				
			||||||
 | 
							return create_err_response(NULL, 501, "DLCX", p->trans);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (endp->wildcarded_req) {
 | 
						if (endp->wildcarded_req) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
@@ -1381,8 +1324,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	/* policy CB */
 | 
						/* policy CB */
 | 
				
			||||||
	if (p->cfg->policy_cb) {
 | 
						if (p->cfg->policy_cb) {
 | 
				
			||||||
		int rc;
 | 
							int rc;
 | 
				
			||||||
		rc = p->cfg->policy_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
							rc = p->cfg->policy_cb(endp, MGCP_ENDP_DLCX, p->trans);
 | 
				
			||||||
				       MGCP_ENDP_DLCX, p->trans);
 | 
					 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "DLCX: rejected by policy\n");
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "DLCX: rejected by policy\n");
 | 
				
			||||||
@@ -1446,8 +1388,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
							p->cfg->change_cb(endp, MGCP_ENDP_DLCX);
 | 
				
			||||||
				  MGCP_ENDP_DLCX);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_SUCCESS]);
 | 
						rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_SUCCESS]);
 | 
				
			||||||
	if (silent)
 | 
						if (silent)
 | 
				
			||||||
@@ -1476,7 +1417,7 @@ static struct msgb *handle_rsip(struct mgcp_parse_data *p)
 | 
				
			|||||||
	LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
 | 
						LOGP(DLMGCP, LOGL_NOTICE, "RSIP: resetting all endpoints ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->cfg->reset_cb)
 | 
						if (p->cfg->reset_cb)
 | 
				
			||||||
		p->cfg->reset_cb(p->endp->tcfg);
 | 
							p->cfg->reset_cb(p->endp->trunk);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1522,37 +1463,37 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Connection keepalive timer, will take care that dummy packets are send
 | 
					/* Connection keepalive timer, will take care that dummy packets are send
 | 
				
			||||||
 * regularly, so that NAT connections stay open */
 | 
					 * regularly, so that NAT connections stay open */
 | 
				
			||||||
static void mgcp_keepalive_timer_cb(void *_tcfg)
 | 
					static void mgcp_keepalive_timer_cb(void *_trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *tcfg = _tcfg;
 | 
						struct mgcp_trunk *trunk = _trunk;
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "triggered trunk %d keepalive timer\n",
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "triggered trunk %d keepalive timer\n",
 | 
				
			||||||
	     tcfg->trunk_nr);
 | 
						     trunk->trunk_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Do not accept invalid configuration values
 | 
						/* Do not accept invalid configuration values
 | 
				
			||||||
	 * valid is MGCP_KEEPALIVE_NEVER, MGCP_KEEPALIVE_ONCE and
 | 
						 * valid is MGCP_KEEPALIVE_NEVER, MGCP_KEEPALIVE_ONCE and
 | 
				
			||||||
	 * values greater 0 */
 | 
						 * values greater 0 */
 | 
				
			||||||
	OSMO_ASSERT(tcfg->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
						OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The dummy packet functionality has been disabled, we will exit
 | 
						/* The dummy packet functionality has been disabled, we will exit
 | 
				
			||||||
	 * immediately, no further timer is scheduled, which means we will no
 | 
						 * immediately, no further timer is scheduled, which means we will no
 | 
				
			||||||
	 * longer send dummy packets even when we did before */
 | 
						 * longer send dummy packets even when we did before */
 | 
				
			||||||
	if (tcfg->keepalive_interval == MGCP_KEEPALIVE_NEVER)
 | 
						if (trunk->keepalive_interval == MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* In cases where only one dummy packet is sent, we do not need
 | 
						/* In cases where only one dummy packet is sent, we do not need
 | 
				
			||||||
	 * the timer since the functions that handle the CRCX and MDCX are
 | 
						 * the timer since the functions that handle the CRCX and MDCX are
 | 
				
			||||||
	 * triggering the sending of the dummy packet. So we behave like in
 | 
						 * triggering the sending of the dummy packet. So we behave like in
 | 
				
			||||||
	 * the  MGCP_KEEPALIVE_NEVER case */
 | 
						 * the  MGCP_KEEPALIVE_NEVER case */
 | 
				
			||||||
	if (tcfg->keepalive_interval == MGCP_KEEPALIVE_ONCE)
 | 
						if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send walk over all endpoints and send out dummy packets through
 | 
						/* Send walk over all endpoints and send out dummy packets through
 | 
				
			||||||
	 * every connection present on each endpoint */
 | 
						 * every connection present on each endpoint */
 | 
				
			||||||
	for (i = 1; i < tcfg->number_endpoints; ++i) {
 | 
						for (i = 1; i < trunk->number_endpoints; ++i) {
 | 
				
			||||||
		struct mgcp_endpoint *endp = &tcfg->endpoints[i];
 | 
							struct mgcp_endpoint *endp = trunk->endpoints[i];
 | 
				
			||||||
		llist_for_each_entry(conn, &endp->conns, entry) {
 | 
							llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
			if (conn->mode == MGCP_CONN_RECV_ONLY)
 | 
								if (conn->mode == MGCP_CONN_RECV_ONLY)
 | 
				
			||||||
				send_dummy(endp, &conn->u.rtp);
 | 
									send_dummy(endp, &conn->u.rtp);
 | 
				
			||||||
@@ -1561,83 +1502,29 @@ static void mgcp_keepalive_timer_cb(void *_tcfg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Schedule the keepalive timer for the next round */
 | 
						/* Schedule the keepalive timer for the next round */
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "rescheduling trunk %d keepalive timer\n",
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "rescheduling trunk %d keepalive timer\n",
 | 
				
			||||||
	     tcfg->trunk_nr);
 | 
						     trunk->trunk_nr);
 | 
				
			||||||
	osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval,
 | 
						osmo_timer_schedule(&trunk->keepalive_timer, trunk->keepalive_interval,
 | 
				
			||||||
			    0);
 | 
								    0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
 | 
					void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tcfg->keepalive_interval = interval;
 | 
						trunk->keepalive_interval = interval;
 | 
				
			||||||
	osmo_timer_setup(&tcfg->keepalive_timer, mgcp_keepalive_timer_cb, tcfg);
 | 
						osmo_timer_setup(&trunk->keepalive_timer, mgcp_keepalive_timer_cb, trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (interval <= 0)
 | 
						if (interval <= 0)
 | 
				
			||||||
		osmo_timer_del(&tcfg->keepalive_timer);
 | 
							osmo_timer_del(&trunk->keepalive_timer);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		osmo_timer_schedule(&tcfg->keepalive_timer,
 | 
							osmo_timer_schedule(&trunk->keepalive_timer,
 | 
				
			||||||
				    tcfg->keepalive_interval, 0);
 | 
									    trunk->keepalive_interval, 0);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	rate_ctr_group_free(rate_ctr_group);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int alloc_mgcp_rate_counters(struct mgcp_trunk_config *trunk, void *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* FIXME: Each new rate counter group requires a unique index. At the
 | 
					 | 
				
			||||||
	 * moment we generate an index using a counter, but perhaps there is
 | 
					 | 
				
			||||||
	 * a better way of assigning indices? */
 | 
					 | 
				
			||||||
	static unsigned int general_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
	static unsigned int crcx_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
	static unsigned int mdcx_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
	static unsigned int dlcx_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
	static unsigned int all_rtp_conn_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (trunk->mgcp_general_ctr_group == NULL) {
 | 
					 | 
				
			||||||
		trunk->mgcp_general_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
 | 
					 | 
				
			||||||
		if (!trunk->mgcp_general_ctr_group)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_general_ctr_group, free_rate_counter_group);
 | 
					 | 
				
			||||||
		general_rate_ctr_index++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (trunk->mgcp_crcx_ctr_group == NULL) {
 | 
					 | 
				
			||||||
		trunk->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
 | 
					 | 
				
			||||||
		if (!trunk->mgcp_crcx_ctr_group)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_crcx_ctr_group, free_rate_counter_group);
 | 
					 | 
				
			||||||
		crcx_rate_ctr_index++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (trunk->mgcp_mdcx_ctr_group == NULL) {
 | 
					 | 
				
			||||||
		trunk->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
 | 
					 | 
				
			||||||
		if (!trunk->mgcp_mdcx_ctr_group)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_mdcx_ctr_group, free_rate_counter_group);
 | 
					 | 
				
			||||||
		mdcx_rate_ctr_index++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (trunk->mgcp_dlcx_ctr_group == NULL) {
 | 
					 | 
				
			||||||
		trunk->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
 | 
					 | 
				
			||||||
		if (!trunk->mgcp_dlcx_ctr_group)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_dlcx_ctr_group, free_rate_counter_group);
 | 
					 | 
				
			||||||
		dlcx_rate_ctr_index++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (trunk->all_rtp_conn_stats == NULL) {
 | 
					 | 
				
			||||||
		trunk->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
 | 
					 | 
				
			||||||
								 all_rtp_conn_rate_ctr_index);
 | 
					 | 
				
			||||||
		if (!trunk->all_rtp_conn_stats)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		talloc_set_destructor(trunk->all_rtp_conn_stats, free_rate_counter_group);
 | 
					 | 
				
			||||||
		all_rtp_conn_rate_ctr_index++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate configuration with default values.
 | 
					/*! allocate configuration with default values.
 | 
				
			||||||
 *  (called once at startup by main function) */
 | 
					 *  (called once at startup by main function) */
 | 
				
			||||||
struct mgcp_config *mgcp_config_alloc(void)
 | 
					struct mgcp_config *mgcp_config_alloc(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* FIXME: This is unrelated to the protocol, put this in some
 | 
				
			||||||
 | 
						 * appropiate place! */
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = talloc_zero(NULL, struct mgcp_config);
 | 
						cfg = talloc_zero(NULL, struct mgcp_config);
 | 
				
			||||||
@@ -1661,113 +1548,19 @@ struct mgcp_config *mgcp_config_alloc(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
 | 
						cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* default trunk handling; TODO: avoid duplication with mgcp_trunk_alloc() below */
 | 
						INIT_LLIST_HEAD(&cfg->trunks);
 | 
				
			||||||
	cfg->trunk.cfg = cfg;
 | 
					
 | 
				
			||||||
	cfg->trunk.trunk_nr = 0;
 | 
						/* Allocate virtual trunk */
 | 
				
			||||||
	cfg->trunk.trunk_type = MGCP_TRUNK_VIRTUAL;
 | 
						if (!mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID)) {
 | 
				
			||||||
	cfg->trunk.audio_name = talloc_strdup(cfg, "AMR/8000");
 | 
					 | 
				
			||||||
	cfg->trunk.audio_payload = 126;
 | 
					 | 
				
			||||||
	cfg->trunk.audio_send_ptime = 1;
 | 
					 | 
				
			||||||
	cfg->trunk.audio_send_name = 1;
 | 
					 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 33;
 | 
					 | 
				
			||||||
	cfg->trunk.omit_rtcp = 0;
 | 
					 | 
				
			||||||
	mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
 | 
					 | 
				
			||||||
	if (alloc_mgcp_rate_counters(&cfg->trunk, cfg) < 0) {
 | 
					 | 
				
			||||||
		talloc_free(cfg);
 | 
							talloc_free(cfg);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&cfg->trunks);
 | 
					        mgcp_ratectr_global_alloc(cfg, &cfg->ratectr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cfg;
 | 
						return cfg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate configuration with default values.
 | 
					 | 
				
			||||||
 *  (called once at startup by VTY)
 | 
					 | 
				
			||||||
 *  \param[in] cfg mgcp configuration
 | 
					 | 
				
			||||||
 *  \param[in] nr trunk number
 | 
					 | 
				
			||||||
 *  \returns pointer to allocated trunk configuration */
 | 
					 | 
				
			||||||
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk_config *trunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	trunk = talloc_zero(cfg, struct mgcp_trunk_config);
 | 
					 | 
				
			||||||
	if (!trunk) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	trunk->cfg = cfg;
 | 
					 | 
				
			||||||
	trunk->trunk_type = MGCP_TRUNK_E1;
 | 
					 | 
				
			||||||
	trunk->trunk_nr = nr;
 | 
					 | 
				
			||||||
	trunk->audio_name = talloc_strdup(cfg, "AMR/8000");
 | 
					 | 
				
			||||||
	trunk->audio_payload = 126;
 | 
					 | 
				
			||||||
	trunk->audio_send_ptime = 1;
 | 
					 | 
				
			||||||
	trunk->audio_send_name = 1;
 | 
					 | 
				
			||||||
	trunk->vty_number_endpoints = 33;
 | 
					 | 
				
			||||||
	trunk->omit_rtcp = 0;
 | 
					 | 
				
			||||||
	mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
 | 
					 | 
				
			||||||
	alloc_mgcp_rate_counters(trunk, trunk);
 | 
					 | 
				
			||||||
	llist_add_tail(&trunk->entry, &cfg->trunks);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return trunk;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! get trunk configuration by trunk number (index).
 | 
					 | 
				
			||||||
 *  \param[in] cfg mgcp configuration
 | 
					 | 
				
			||||||
 *  \param[in] index trunk number
 | 
					 | 
				
			||||||
 *  \returns pointer to trunk configuration, NULL on error */
 | 
					 | 
				
			||||||
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_trunk_config *trunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	llist_for_each_entry(trunk, &cfg->trunks, entry)
 | 
					 | 
				
			||||||
	    if (trunk->trunk_nr == index)
 | 
					 | 
				
			||||||
		return trunk;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! allocate endpoints and set default values.
 | 
					 | 
				
			||||||
 *  (called once at startup by VTY)
 | 
					 | 
				
			||||||
 *  \param[in] tcfg trunk configuration
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -1 on failure */
 | 
					 | 
				
			||||||
int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tcfg->endpoints = _talloc_zero_array(tcfg->cfg,
 | 
					 | 
				
			||||||
					     sizeof(struct mgcp_endpoint),
 | 
					 | 
				
			||||||
					     tcfg->vty_number_endpoints,
 | 
					 | 
				
			||||||
					     "endpoints");
 | 
					 | 
				
			||||||
	if (!tcfg->endpoints)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < tcfg->vty_number_endpoints; ++i) {
 | 
					 | 
				
			||||||
		INIT_LLIST_HEAD(&tcfg->endpoints[i].conns);
 | 
					 | 
				
			||||||
		tcfg->endpoints[i].cfg = tcfg->cfg;
 | 
					 | 
				
			||||||
		tcfg->endpoints[i].tcfg = tcfg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (tcfg->trunk_type) {
 | 
					 | 
				
			||||||
		case MGCP_TRUNK_VIRTUAL:
 | 
					 | 
				
			||||||
			tcfg->endpoints[i].type = &ep_typeset.rtp;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case MGCP_TRUNK_E1:
 | 
					 | 
				
			||||||
			/* FIXME: Implement E1 allocation */
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_FATAL, "E1 trunks not implemented!\n");
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
 | 
					 | 
				
			||||||
				   tcfg->trunk_type, __FILE__, __LINE__);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tcfg->number_endpoints = tcfg->vty_number_endpoints;
 | 
					 | 
				
			||||||
	alloc_mgcp_rate_counters(tcfg, tcfg->cfg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
 | 
					static int send_agent(struct mgcp_config *cfg, const char *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return write(cfg->gw_fd.bfd.fd, buf, len);
 | 
						return write(cfg->gw_fd.bfd.fd, buf, len);
 | 
				
			||||||
@@ -1798,17 +1591,16 @@ int mgcp_send_reset_all(struct mgcp_config *cfg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! Reset a single endpoint by sending RSIP message to self.
 | 
					/*! Reset a single endpoint by sending RSIP message to self.
 | 
				
			||||||
 *  (called by VTY)
 | 
					 *  (called by VTY)
 | 
				
			||||||
 *  \param[in] endp trunk endpoint
 | 
					 *  \param[in] endp to reset
 | 
				
			||||||
 *  \param[in] endpoint number
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -1 on error */
 | 
					 *  \returns 0 on success, -1 on error */
 | 
				
			||||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint)
 | 
					int mgcp_send_reset_ep(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char buf[MGCP_ENDPOINT_MAXLEN + 128];
 | 
						char buf[MGCP_ENDPOINT_MAXLEN + 128];
 | 
				
			||||||
	int len;
 | 
						int len;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = snprintf(buf, sizeof(buf),
 | 
						len = snprintf(buf, sizeof(buf),
 | 
				
			||||||
		       "RSIP 39 %x@%s MGCP 1.0\r\n", endpoint, endp->cfg->domain);
 | 
							       "RSIP 39 %s MGCP 1.0\r\n", endp->name);
 | 
				
			||||||
	if (len < 0)
 | 
						if (len < 0)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										229
									
								
								src/libosmo-mgcp/mgcp_ratectr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/libosmo-mgcp/mgcp_ratectr.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,229 @@
 | 
				
			|||||||
 | 
					/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
 | 
				
			||||||
 | 
					/* rate-counter implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by On-Waves
 | 
				
			||||||
 | 
					 * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * 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 <errno.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stats.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_ratectr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
				
			||||||
 | 
						/* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_MSGS_TOTAL] = { "mgcp:rx_msgs", "total number of MGCP messages received." },
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = { "mgcp:rx_msgs_retransmitted", "number of received retransmissions." },
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_MSGS_HANDLED] = { "mgcp:rx_msgs_handled", "number of handled MGCP messages." },
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_MSGS_UNHANDLED] = { "mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages." },
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_FAIL_MSG_PARSE] = { "mgcp:err_rx_msg_parse", "error parsing MGCP message." },
 | 
				
			||||||
 | 
						[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] =
 | 
				
			||||||
 | 
						    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "mgcp",
 | 
				
			||||||
 | 
						.group_description = "mgcp general statistics",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = mgcp_general_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
				
			||||||
 | 
						[MGCP_CRCX_SUCCESS] = { "crcx:success", "CRCX command processed successfully." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_BAD_ACTION] = { "crcx:bad_action", "bad action in CRCX command." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in CRCX command." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_MISSING_CALLID] = { "crcx:missing_callid", "missing CallId in CRCX command." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_INVALID_MODE] = { "crcx:invalid_mode", "invalid connection mode in CRCX command." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = { "crcx:limit_exceeded", "limit of concurrent connections was reached." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_UNKNOWN_CALLID] = { "crcx:unkown_callid", "unknown CallId in CRCX command." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_ALLOC_CONN] = { "crcx:alloc_conn_fail", "connection allocation failure." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
				
			||||||
 | 
						    { "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_REJECTED_BY_POLICY] = { "crcx:conn_rejected", "connection rejected by policy." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
 | 
						[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "crcx",
 | 
				
			||||||
 | 
						.group_description = "crxc statistics",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = mgcp_crcx_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
 | 
				
			||||||
 | 
						[MGCP_MDCX_SUCCESS] = { "mdcx:success", "MDCX command processed successfully." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_WILDCARD] = { "mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_NO_CONN] = { "mdcx:no_conn", "endpoint specified in MDCX command has no active connections." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_INVALID_CALLID] = { "mdcx:callid", "invalid CallId specified in MDCX command." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_INVALID_CONNID] = { "mdcx:connid", "invalid connection ID specified in MDCX command." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in MDCX command." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_NO_CONNID] = { "mdcx:no_connid", "no connection ID specified in MDCX command." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_CONN_NOT_FOUND] =
 | 
				
			||||||
 | 
						    { "mdcx:conn_not_found", "connection specified in MDCX command does not exist." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_INVALID_MODE] = { "mdcx:invalid_mode", "invalid connection mode in MDCX command." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
 | 
				
			||||||
 | 
						    { "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_REJECTED_BY_POLICY] = { "mdcx:conn_rejected", "connection rejected by policy." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_DEFERRED_BY_POLICY] = { "mdcx:conn_deferred", "connection deferred by policy." },
 | 
				
			||||||
 | 
						[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "mdcx",
 | 
				
			||||||
 | 
						.group_description = "mdcx statistics",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = mgcp_mdcx_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
				
			||||||
 | 
						[MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_WILDCARD] = { "dlcx:wildcard", "wildcard names in DLCX commands are unsupported." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_INVALID_CALLID] =
 | 
				
			||||||
 | 
						    { "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_INVALID_CONNID] =
 | 
				
			||||||
 | 
						    { "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_REJECTED_BY_POLICY] = { "dlcx:rejected", "connection deletion rejected by policy." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_DEFERRED_BY_POLICY] = { "dlcx:deferred", "connection deletion deferred by policy." },
 | 
				
			||||||
 | 
						[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "dlcx",
 | 
				
			||||||
 | 
						.group_description = "dlcx statistics",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = mgcp_dlcx_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
 | 
				
			||||||
 | 
						[E1_I460_TRAU_RX_FAIL_CTR] = {"e1:rx_fail", "Inbound I.460 TRAU failures."},
 | 
				
			||||||
 | 
						[E1_I460_TRAU_TX_FAIL_CTR] = {"e1:tx_fail", "Outbound I.460 TRAU failures."},
 | 
				
			||||||
 | 
						[E1_I460_TRAU_MUX_EMPTY_CTR] = {"e1:i460", "Outbound I.460 MUX queue empty."}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "e1",
 | 
				
			||||||
 | 
						.group_description = "e1 statistics",
 | 
				
			||||||
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(e1_rate_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = e1_rate_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "all_rtp_conn",
 | 
				
			||||||
 | 
						.group_description = "aggregated statistics for all rtp connections",
 | 
				
			||||||
 | 
						.class_id = 1,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rate_ctr_group_free(rate_ctr_group);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate global rate counters into a given rate counter struct
 | 
				
			||||||
 | 
					 *  (called once at startup)
 | 
				
			||||||
 | 
					 *  \param[in] ctx talloc context.
 | 
				
			||||||
 | 
					 *  \param[out] ratectr struct that holds the counters
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure */
 | 
				
			||||||
 | 
					int mgcp_ratectr_global_alloc(void *ctx, struct mgcp_ratectr_global *ratectr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* FIXME: Each new rate counter group requires a unique index. At the
 | 
				
			||||||
 | 
						 * moment we generate an index using a counter, but perhaps there is
 | 
				
			||||||
 | 
						 * a better way of assigning indices? */
 | 
				
			||||||
 | 
						static unsigned int general_rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ratectr->mgcp_general_ctr_group == NULL) {
 | 
				
			||||||
 | 
							ratectr->mgcp_general_ctr_group =
 | 
				
			||||||
 | 
							    rate_ctr_group_alloc(ctx, &mgcp_general_ctr_group_desc, general_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->mgcp_general_ctr_group)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->mgcp_general_ctr_group, free_rate_counter_group);
 | 
				
			||||||
 | 
							general_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate trunk specific rate counters into a given rate counter struct
 | 
				
			||||||
 | 
					 *  (called once on trunk initialization)
 | 
				
			||||||
 | 
					 *  \param[in] ctx talloc context.
 | 
				
			||||||
 | 
					 *  \param[out] ratectr struct that holds the counters
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure */
 | 
				
			||||||
 | 
					int mgcp_ratectr_trunk_alloc(void *ctx, struct mgcp_ratectr_trunk *ratectr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* FIXME: see comment in mgcp_ratectr_global_alloc()  */
 | 
				
			||||||
 | 
						static unsigned int crcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static unsigned int mdcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static unsigned int dlcx_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static unsigned int all_rtp_conn_rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
				
			||||||
 | 
							ratectr->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->mgcp_crcx_ctr_group)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->mgcp_crcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
 | 
							crcx_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->mgcp_mdcx_ctr_group == NULL) {
 | 
				
			||||||
 | 
							ratectr->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->mgcp_mdcx_ctr_group)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->mgcp_mdcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
 | 
							mdcx_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->mgcp_dlcx_ctr_group == NULL) {
 | 
				
			||||||
 | 
							ratectr->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->mgcp_dlcx_ctr_group)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->mgcp_dlcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
 | 
							dlcx_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_rtp_conn_stats == NULL) {
 | 
				
			||||||
 | 
							ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
 | 
				
			||||||
 | 
													 all_rtp_conn_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->all_rtp_conn_stats)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->all_rtp_conn_stats, free_rate_counter_group);
 | 
				
			||||||
 | 
							all_rtp_conn_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->e1_stats == NULL) {
 | 
				
			||||||
 | 
							ratectr->e1_stats = rate_ctr_group_alloc(ctx, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!ratectr->e1_stats)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							talloc_set_destructor(ratectr->e1_stats, free_rate_counter_group);
 | 
				
			||||||
 | 
							mdcx_rate_ctr_index++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -21,12 +21,19 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
@@ -255,6 +262,42 @@ error:
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int audio_ip_from_sdp(struct osmo_sockaddr *dst_addr, char *sdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool is_ipv6;
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
						if (strncmp("c=IN IP", sdp, 7) != 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						sdp += 7;
 | 
				
			||||||
 | 
						if (*sdp == '6')
 | 
				
			||||||
 | 
						       is_ipv6 = true;
 | 
				
			||||||
 | 
						else if (*sdp == '4')
 | 
				
			||||||
 | 
						       is_ipv6 = false;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						       return -1;
 | 
				
			||||||
 | 
						sdp++;
 | 
				
			||||||
 | 
						if (*sdp != ' ')
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						sdp++;
 | 
				
			||||||
 | 
						if (is_ipv6) {
 | 
				
			||||||
 | 
							/* 45 = INET6_ADDRSTRLEN -1 */
 | 
				
			||||||
 | 
							if (sscanf(sdp, "%45s", ipbuf) != 1)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET6, ipbuf, &dst_addr->u.sin6.sin6_addr) != 1)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							dst_addr->u.sa.sa_family = AF_INET6;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* 15 = INET_ADDRSTRLEN -1 */
 | 
				
			||||||
 | 
							if (sscanf(sdp, "%15s", ipbuf) != 1)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							if (inet_pton(AF_INET, ipbuf, &dst_addr->u.sin.sin_addr) != 1)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							dst_addr->u.sa.sa_family = AF_INET;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Pick optional fmtp parameters by payload type, if there are no fmtp
 | 
					/* Pick optional fmtp parameters by payload type, if there are no fmtp
 | 
				
			||||||
 * parameters, a nullpointer is returned */
 | 
					 * parameters, a nullpointer is returned */
 | 
				
			||||||
static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
 | 
					static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
 | 
				
			||||||
@@ -285,6 +328,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
						struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int fmtp_used = 0;
 | 
						unsigned int fmtp_used = 0;
 | 
				
			||||||
	struct mgcp_codec_param *codec_param;
 | 
						struct mgcp_codec_param *codec_param;
 | 
				
			||||||
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
@@ -294,7 +338,6 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	int ptime, ptime2 = 0;
 | 
						int ptime, ptime2 = 0;
 | 
				
			||||||
	char audio_name[64];
 | 
						char audio_name[64];
 | 
				
			||||||
	int port, rc;
 | 
						int port, rc;
 | 
				
			||||||
	char ipv4[16];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
@@ -351,17 +394,16 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
				codecs_used = rc;
 | 
									codecs_used = rc;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'c':
 | 
							case 'c':
 | 
				
			||||||
 | 
								if (audio_ip_from_sdp(&rtp->addr, line) < 0)
 | 
				
			||||||
			if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
 | 
									return -1;
 | 
				
			||||||
				inet_aton(ipv4, &rtp->addr);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if (p->endp)
 | 
								if (p->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,
 | 
									LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d on 0x%x\n",
 | 
									     "Unhandled SDP option: '%c'/%d on %s\n",
 | 
				
			||||||
				     line[0], line[0],
 | 
									     line[0], line[0], endp->name);
 | 
				
			||||||
				     ENDPOINT_NUMBER(p->endp));
 | 
					 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_NOTICE,
 | 
									LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
				     "Unhandled SDP option: '%c'/%d\n",
 | 
									     "Unhandled SDP option: '%c'/%d\n",
 | 
				
			||||||
@@ -381,14 +423,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
							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_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(tmp_ctx);
 | 
						talloc_free(tmp_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
						     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
				
			||||||
	     ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
 | 
						     ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
				
			||||||
	     rtp->packet_duration_ms);
 | 
						     rtp->packet_duration_ms);
 | 
				
			||||||
	if (codecs_used == 0)
 | 
						if (codecs_used == 0)
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
				
			||||||
@@ -476,6 +518,8 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < fmtp_params_len; i++) {
 | 
						for (i = 0; i < fmtp_params_len; i++) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
							rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Add amr octet align parameter */
 | 
							/* Add amr octet align parameter */
 | 
				
			||||||
		if (fmtp_params[i].param.amr_octet_aligned_present) {
 | 
							if (fmtp_params[i].param.amr_octet_aligned_present) {
 | 
				
			||||||
@@ -494,7 +538,7 @@ static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsign
 | 
				
			|||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
 | 
							rc = msgb_printf(sdp, "\r\n");
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -522,6 +566,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	int local_port;
 | 
						int local_port;
 | 
				
			||||||
	struct sdp_fmtp_param fmtp_params[1];
 | 
						struct sdp_fmtp_param fmtp_params[1];
 | 
				
			||||||
        unsigned int fmtp_params_len = 0;
 | 
					        unsigned int fmtp_params_len = 0;
 | 
				
			||||||
 | 
						bool addr_is_v6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
@@ -536,12 +581,16 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	audio_name = codec->audio_name;
 | 
						audio_name = codec->audio_name;
 | 
				
			||||||
	payload_type = codec->payload_type;
 | 
						payload_type = codec->payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr_is_v6 = osmo_ip_str_type(addr) == AF_INET6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = msgb_printf(sdp,
 | 
						rc = msgb_printf(sdp,
 | 
				
			||||||
			 "v=0\r\n"
 | 
								 "v=0\r\n"
 | 
				
			||||||
			 "o=- %s 23 IN IP4 %s\r\n"
 | 
								 "o=- %s 23 IN IP%c %s\r\n"
 | 
				
			||||||
			 "s=-\r\n"
 | 
								 "s=-\r\n"
 | 
				
			||||||
			 "c=IN IP4 %s\r\n"
 | 
								 "c=IN IP%c %s\r\n"
 | 
				
			||||||
			 "t=0 0\r\n", conn->conn->id, addr, addr);
 | 
								 "t=0 0\r\n", conn->conn->id,
 | 
				
			||||||
 | 
								 addr_is_v6 ? '6' : '4', addr,
 | 
				
			||||||
 | 
								 addr_is_v6 ? '6' : '4', addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		goto buffer_too_small;
 | 
							goto buffer_too_small;
 | 
				
			||||||
@@ -557,7 +606,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (endp->tcfg->audio_send_name) {
 | 
							if (endp->trunk->audio_send_name) {
 | 
				
			||||||
			rc = add_rtpmap(sdp, payload_type, audio_name);
 | 
								rc = add_rtpmap(sdp, payload_type, audio_name);
 | 
				
			||||||
			if (rc < 0)
 | 
								if (rc < 0)
 | 
				
			||||||
				goto buffer_too_small;
 | 
									goto buffer_too_small;
 | 
				
			||||||
@@ -573,7 +622,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
 | 
						if (conn->end.packet_duration_ms > 0 && endp->trunk->audio_send_ptime) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "a=ptime:%u\r\n",
 | 
							rc = msgb_printf(sdp, "a=ptime:%u\r\n",
 | 
				
			||||||
				 conn->end.packet_duration_ms);
 | 
									 conn->end.packet_duration_ms);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,10 +22,12 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_stat.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_stat.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
 | 
					/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
 | 
				
			||||||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
					void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										255
									
								
								src/libosmo-mgcp/mgcp_trunk.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								src/libosmo-mgcp/mgcp_trunk.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,255 @@
 | 
				
			|||||||
 | 
					/* Trunk handling */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
 | 
				
			||||||
 | 
					 * (C) 2009-2012 by On-Waves
 | 
				
			||||||
 | 
					 * (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * 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 <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate trunk and add it (if required) to the trunk list.
 | 
				
			||||||
 | 
					 *  (called once at startup by VTY).
 | 
				
			||||||
 | 
					 *  \param[in] cfg mgcp configuration.
 | 
				
			||||||
 | 
					 *  \param[in] ttype trunk type.
 | 
				
			||||||
 | 
					 *  \param[in] nr trunk number.
 | 
				
			||||||
 | 
					 *  \returns pointer to allocated trunk, NULL on failure. */
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trunk = talloc_zero(cfg, struct mgcp_trunk);
 | 
				
			||||||
 | 
						if (!trunk) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trunk->cfg = cfg;
 | 
				
			||||||
 | 
						trunk->trunk_type = ttype;
 | 
				
			||||||
 | 
						trunk->trunk_nr = nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trunk->audio_send_ptime = 1;
 | 
				
			||||||
 | 
						trunk->audio_send_name = 1;
 | 
				
			||||||
 | 
						trunk->v.vty_number_endpoints = 512;
 | 
				
			||||||
 | 
						trunk->omit_rtcp = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_add_tail(&trunk->entry, &cfg->trunks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mgcp_ratectr_trunk_alloc(cfg, &trunk->ratectr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return trunk;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! allocate endpoints and set default values
 | 
				
			||||||
 | 
					 *  (called once at startup by VTY).
 | 
				
			||||||
 | 
					 *  \param[in] trunk trunk configuration.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on failure. */
 | 
				
			||||||
 | 
					int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						unsigned int number_endpoints;
 | 
				
			||||||
 | 
						unsigned int first_endpoint_nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This function is called once on startup by the VTY to allocate the
 | 
				
			||||||
 | 
						 * endpoints. The number of endpoints must not change througout the
 | 
				
			||||||
 | 
						 * runtime of the MGW */
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk->number_endpoints == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk->endpoints == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							/* Due to historical reasons the endpoints on the virtual
 | 
				
			||||||
 | 
							 * trunk start counting at 1. */
 | 
				
			||||||
 | 
							first_endpoint_nr = 1;
 | 
				
			||||||
 | 
							number_endpoints = trunk->v.vty_number_endpoints;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							/* The first timeslot on an E1 line is reserved for framing
 | 
				
			||||||
 | 
							 * and alignment and can not be used for audio transport */
 | 
				
			||||||
 | 
						        first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
 | 
				
			||||||
 | 
							number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure the amount of requested endpoints does not execeed
 | 
				
			||||||
 | 
						 * sane limits. The VTY already limits the possible amount,
 | 
				
			||||||
 | 
						 * however miss-initialization of the struct or memory corruption
 | 
				
			||||||
 | 
						 * could still lead to an excessive allocation of endpoints, so
 | 
				
			||||||
 | 
						 * better stop early if that is the case. */
 | 
				
			||||||
 | 
						OSMO_ASSERT(number_endpoints < 65534);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* allocate pointer array for the endpoints */
 | 
				
			||||||
 | 
						trunk->endpoints = talloc_zero_array(trunk->cfg, struct mgcp_endpoint*,
 | 
				
			||||||
 | 
										     number_endpoints);
 | 
				
			||||||
 | 
						if (!trunk->endpoints)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create endpoints */
 | 
				
			||||||
 | 
						for (i = 0; i < number_endpoints; i++) {
 | 
				
			||||||
 | 
							endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
 | 
				
			||||||
 | 
							if (!endp) {
 | 
				
			||||||
 | 
								talloc_free(trunk->endpoints);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							trunk->endpoints[i] = endp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* make the endpoints we just created available to the MGW code */
 | 
				
			||||||
 | 
						trunk->number_endpoints = number_endpoints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Equip trunk with endpoints and resources
 | 
				
			||||||
 | 
					 *  (called once at startup by VTY).
 | 
				
			||||||
 | 
					 *  \param[in] trunk trunk configuration.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on failure. */
 | 
				
			||||||
 | 
					int mgcp_trunk_equip(struct mgcp_trunk *trunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Allocate endpoints */
 | 
				
			||||||
 | 
						if(mgcp_trunk_alloc_endpts(trunk) != 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Allocate resources */
 | 
				
			||||||
 | 
						switch (trunk->trunk_type) {
 | 
				
			||||||
 | 
						case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
 | 
							/* No additional initaliziation required here, virtual
 | 
				
			||||||
 | 
							 * endpoints will open/close network sockets themselves
 | 
				
			||||||
 | 
							 * on demand. */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
							/* The TS initalization happens once on startup for all
 | 
				
			||||||
 | 
							 * timeslots. This only affects the i460 multiplexer. Until
 | 
				
			||||||
 | 
							 * now no E1 resources are claimed yet. This happens on demand
 | 
				
			||||||
 | 
							 * when the related endpoint is actually used */
 | 
				
			||||||
 | 
							memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));
 | 
				
			||||||
 | 
							for (i = 0; i < (NUM_E1_TS-1); i++)
 | 
				
			||||||
 | 
								osmo_i460_ts_init(&trunk->e1.i460_ts[i]);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! get trunk configuration by trunk number (index).
 | 
				
			||||||
 | 
					 *  \param[in] cfg mgcp configuration.
 | 
				
			||||||
 | 
					 *  \param[in] ttype trunk type.
 | 
				
			||||||
 | 
					 *  \param[in] nr trunk number.
 | 
				
			||||||
 | 
					 *  \returns pointer to trunk configuration, NULL on error. */
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(trunk, &cfg->trunks, entry) {
 | 
				
			||||||
 | 
							if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
 | 
				
			||||||
 | 
								return trunk;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Made public for unit-testing, do not use from outside this file */
 | 
				
			||||||
 | 
					int e1_trunk_nr_from_epname(const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long int trunk_nr;
 | 
				
			||||||
 | 
						size_t prefix_len;
 | 
				
			||||||
 | 
						char *str_trunk_nr_end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
 | 
				
			||||||
 | 
						if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						errno = 0;
 | 
				
			||||||
 | 
						trunk_nr = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
 | 
				
			||||||
 | 
						if (errno == ERANGE || trunk_nr > 64
 | 
				
			||||||
 | 
						    || epname + prefix_len == str_trunk_nr_end
 | 
				
			||||||
 | 
						    || str_trunk_nr_end[0] != '/')
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return trunk_nr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Find a trunk by the trunk prefix in the endpoint name.
 | 
				
			||||||
 | 
					 *  \param[in] epname endpoint name with trunk prefix to look up.
 | 
				
			||||||
 | 
					 *  \param[in] cfg that contains the trunks where the endpoint is located.
 | 
				
			||||||
 | 
					 *  \returns trunk or NULL if trunk was not found. */
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t prefix_len;
 | 
				
			||||||
 | 
						char epname_lc[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						int trunk_nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
 | 
				
			||||||
 | 
						epname = epname_lc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
 | 
				
			||||||
 | 
						if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
 | 
				
			||||||
 | 
							return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname(epname);
 | 
				
			||||||
 | 
						if (trunk_nr >= 0)
 | 
				
			||||||
 | 
							return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Earlier versions of osmo-mgw were accepting endpoint names
 | 
				
			||||||
 | 
						 * without trunk prefix. This is normally not allowed, each MGCP
 | 
				
			||||||
 | 
						 * request should supply an endpoint name with trunk prefix.
 | 
				
			||||||
 | 
						 * However in order to stay compatible with old versions of
 | 
				
			||||||
 | 
						 * osmo-bsc and osmo-msc we still accept endpoint names without
 | 
				
			||||||
 | 
						 * trunk prefix and just assume that the virtual trunk should
 | 
				
			||||||
 | 
						 * be selected. There is even a TTCN3 test for this, see also:
 | 
				
			||||||
 | 
						 * MGCP_Test.TC_crcx_noprefix */
 | 
				
			||||||
 | 
						if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
 | 
				
			||||||
 | 
							     MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
 | 
				
			||||||
 | 
							return  mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Find a trunk (E1) by its associated E1 line number.
 | 
				
			||||||
 | 
					 *  \param[in] num e1 line number.
 | 
				
			||||||
 | 
					 *  \returns trunk or NULL if trunk was not found. */
 | 
				
			||||||
 | 
					struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*! When used on trunks other than E1, the result will always be NULL. */
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(trunk, &cfg->trunks, entry) {
 | 
				
			||||||
 | 
							if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)
 | 
				
			||||||
 | 
								return trunk;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -11,6 +11,8 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMOCTRL_CFLAGS) \
 | 
						$(LIBOSMOCTRL_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMONETIF_CFLAGS) \
 | 
						$(LIBOSMONETIF_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_CFLAGS) \
 | 
				
			||||||
	$(COVERAGE_CFLAGS) \
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,4 +31,6 @@ osmo_mgw_LDADD = \
 | 
				
			|||||||
	$(LIBOSMOGSM_LIBS) \
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
	$(LIBOSMOCTRL_LIBS) \
 | 
						$(LIBOSMOCTRL_LIBS) \
 | 
				
			||||||
	$(LIBOSMONETIF_LIBS) \
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_LIBS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,14 +30,17 @@
 | 
				
			|||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/vty.h>
 | 
					#include <osmocom/mgcp/vty.h>
 | 
				
			||||||
#include <osmocom/mgcp/debug.h>
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_ctrl.h>
 | 
					#include <osmocom/mgcp/mgcp_ctrl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
@@ -57,6 +60,9 @@
 | 
				
			|||||||
#include <osmocom/vty/command.h>
 | 
					#include <osmocom/vty/command.h>
 | 
				
			||||||
#include <osmocom/vty/stats.h>
 | 
					#include <osmocom/vty/stats.h>
 | 
				
			||||||
#include <osmocom/vty/misc.h>
 | 
					#include <osmocom/vty/misc.h>
 | 
				
			||||||
 | 
					#include <osmocom/vty/cpu_sched_vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/abis/abis.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../bscconfig.h"
 | 
					#include "../../bscconfig.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -71,7 +77,7 @@
 | 
				
			|||||||
/* FIXME: Make use of the rtp proxy code */
 | 
					/* FIXME: Make use of the rtp proxy code */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_config *cfg;
 | 
					static struct mgcp_config *cfg;
 | 
				
			||||||
static struct mgcp_trunk_config *reset_trunk;
 | 
					static struct mgcp_trunk *reset_trunk;
 | 
				
			||||||
static int reset_endpoints = 0;
 | 
					static int reset_endpoints = 0;
 | 
				
			||||||
static int daemonize = 0;
 | 
					static int daemonize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +93,7 @@ const char *osmomgw_copyright =
 | 
				
			|||||||
static char *config_file = "osmo-mgw.cfg";
 | 
					static char *config_file = "osmo-mgw.cfg";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* used by msgb and mgcp */
 | 
					/* used by msgb and mgcp */
 | 
				
			||||||
void *tall_bsc_ctx = NULL;
 | 
					void *tall_mgw_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_help()
 | 
					static void print_help()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -97,18 +103,21 @@ static void print_help()
 | 
				
			|||||||
	printf(" -s --disable-color\n");
 | 
						printf(" -s --disable-color\n");
 | 
				
			||||||
	printf(" -D --daemonize Fork the process into a background daemon\n");
 | 
						printf(" -D --daemonize Fork the process into a background daemon\n");
 | 
				
			||||||
	printf(" -V --version Print the version number\n");
 | 
						printf(" -V --version Print the version number\n");
 | 
				
			||||||
 | 
						printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_options(int argc, char **argv)
 | 
					static void handle_options(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	while (1) {
 | 
						while (1) {
 | 
				
			||||||
		int option_index = 0, c;
 | 
							int option_index = 0, c;
 | 
				
			||||||
 | 
							static int long_option = 0;
 | 
				
			||||||
		static struct option long_options[] = {
 | 
							static struct option long_options[] = {
 | 
				
			||||||
			{"help", 0, 0, 'h'},
 | 
								{"help", 0, 0, 'h'},
 | 
				
			||||||
			{"config-file", 1, 0, 'c'},
 | 
								{"config-file", 1, 0, 'c'},
 | 
				
			||||||
			{"daemonize", 0, 0, 'D'},
 | 
								{"daemonize", 0, 0, 'D'},
 | 
				
			||||||
			{"version", 0, 0, 'V'},
 | 
								{"version", 0, 0, 'V'},
 | 
				
			||||||
			{"disable-color", 0, 0, 's'},
 | 
								{"disable-color", 0, 0, 's'},
 | 
				
			||||||
 | 
								{"vty-ref-xml", 0, &long_option, 1},
 | 
				
			||||||
			{0, 0, 0, 0},
 | 
								{0, 0, 0, 0},
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,8 +131,17 @@ static void handle_options(int argc, char **argv)
 | 
				
			|||||||
			print_help();
 | 
								print_help();
 | 
				
			||||||
			exit(0);
 | 
								exit(0);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								switch (long_option) {
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									vty_dump_xml_ref(stdout);
 | 
				
			||||||
 | 
									exit(0);
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									fprintf(stderr, "error parsing cmdline options\n");
 | 
				
			||||||
 | 
									exit(2);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		case 'c':
 | 
							case 'c':
 | 
				
			||||||
			config_file = talloc_strdup(tall_bsc_ctx, optarg);
 | 
								config_file = talloc_strdup(tall_mgw_ctx, optarg);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 's':
 | 
							case 's':
 | 
				
			||||||
			log_set_use_color(osmo_stderr_target, 0);
 | 
								log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
@@ -148,20 +166,20 @@ static void handle_options(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Callback function to be called when the RSIP ("Reset in Progress") mgcp
 | 
					/* Callback function to be called when the RSIP ("Reset in Progress") mgcp
 | 
				
			||||||
 * command is received */
 | 
					 * command is received */
 | 
				
			||||||
static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg)
 | 
					static int mgcp_rsip_cb(struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Set flag so that, when read_call_agent() is called next time
 | 
						/* Set flag so that, when read_call_agent() is called next time
 | 
				
			||||||
	 * the reset can progress */
 | 
						 * the reset can progress */
 | 
				
			||||||
	reset_endpoints = 1;
 | 
						reset_endpoints = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reset_trunk = tcfg;
 | 
						reset_trunk = trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
					static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sockaddr_in addr;
 | 
						struct osmo_sockaddr addr;
 | 
				
			||||||
	socklen_t slen = sizeof(addr);
 | 
						socklen_t slen = sizeof(addr);
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
	struct msgb *resp;
 | 
						struct msgb *resp;
 | 
				
			||||||
@@ -187,7 +205,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
	msgb_reset(msg);
 | 
						msgb_reset(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (resp) {
 | 
						if (resp) {
 | 
				
			||||||
		sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
 | 
							sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, &addr.u.sa, sizeof(addr));
 | 
				
			||||||
		msgb_free(resp);
 | 
							msgb_free(resp);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,7 +221,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
		/* Walk over all endpoints and trigger a release, this will release all
 | 
							/* Walk over all endpoints and trigger a release, this will release all
 | 
				
			||||||
		 * endpoints, possible open connections are forcefully dropped */
 | 
							 * endpoints, possible open connections are forcefully dropped */
 | 
				
			||||||
		for (i = 1; i < reset_trunk->number_endpoints; ++i)
 | 
							for (i = 1; i < reset_trunk->number_endpoints; ++i)
 | 
				
			||||||
			mgcp_endp_release(&reset_trunk->endpoints[i]);
 | 
								mgcp_endp_release(reset_trunk->endpoints[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -255,7 +273,13 @@ static const struct log_info_cat log_categories[] = {
 | 
				
			|||||||
		  .description = "RTP stream handling",
 | 
							  .description = "RTP stream handling",
 | 
				
			||||||
		  .color = "\033[1;30m",
 | 
							  .color = "\033[1;30m",
 | 
				
			||||||
		  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
		  },
 | 
						},
 | 
				
			||||||
 | 
						[DE1] = {
 | 
				
			||||||
 | 
							  .name = "DE1",
 | 
				
			||||||
 | 
							  .description = "E1 line handling",
 | 
				
			||||||
 | 
							  .color = "\033[1;31m",
 | 
				
			||||||
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct log_info log_info = {
 | 
					const struct log_info log_info = {
 | 
				
			||||||
@@ -268,37 +292,44 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	unsigned int flags;
 | 
						unsigned int flags;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
 | 
						tall_mgw_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
 | 
				
			||||||
	vty_info.tall_ctx = tall_bsc_ctx;
 | 
						vty_info.tall_ctx = tall_mgw_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_talloc_ctx_init(tall_bsc_ctx, 0);
 | 
						msgb_talloc_ctx_init(tall_mgw_ctx, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_init_ignore_signals();
 | 
						osmo_init_ignore_signals();
 | 
				
			||||||
	osmo_init_logging2(tall_bsc_ctx, &log_info);
 | 
						osmo_init_logging2(tall_mgw_ctx, &log_info);
 | 
				
			||||||
 | 
						libosmo_abis_init(tall_mgw_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
	if (!cfg)
 | 
						if (!cfg)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_info.copyright = osmomgw_copyright;
 | 
						vty_info.copyright = osmomgw_copyright;
 | 
				
			||||||
 | 
						vty_info.usr_attr_desc[MGW_CMD_ATTR_NEWCONN] = \
 | 
				
			||||||
 | 
							"This command applies when a new connection is created";
 | 
				
			||||||
 | 
						vty_info.usr_attr_letters[MGW_CMD_ATTR_NEWCONN] = 'n';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_init(&vty_info);
 | 
						vty_init(&vty_info);
 | 
				
			||||||
	logging_vty_add_cmds();
 | 
						logging_vty_add_cmds();
 | 
				
			||||||
	osmo_talloc_vty_add_cmds();
 | 
						osmo_talloc_vty_add_cmds();
 | 
				
			||||||
	osmo_stats_vty_add_cmds();
 | 
						osmo_stats_vty_add_cmds();
 | 
				
			||||||
	mgcp_vty_init();
 | 
						mgcp_vty_init();
 | 
				
			||||||
	ctrl_vty_init(cfg);
 | 
						ctrl_vty_init(cfg);
 | 
				
			||||||
 | 
						e1inp_vty_init();
 | 
				
			||||||
 | 
						osmo_cpu_sched_vty_init(tall_mgw_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle_options(argc, argv);
 | 
						handle_options(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_init(tall_bsc_ctx);
 | 
						rate_ctr_init(tall_mgw_ctx);
 | 
				
			||||||
	osmo_stats_init(tall_bsc_ctx);
 | 
						osmo_stats_init(tall_mgw_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
 | 
						rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* start telnet after reading config for vty_get_bind_addr() */
 | 
						/* start telnet after reading config for vty_get_bind_addr() */
 | 
				
			||||||
	rc = telnet_init_dynif(tall_bsc_ctx, NULL,
 | 
						rc = telnet_init_dynif(tall_mgw_ctx, NULL,
 | 
				
			||||||
			       vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
 | 
								       vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
@@ -318,7 +349,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	if (cfg->call_agent_addr)
 | 
						if (cfg->call_agent_addr)
 | 
				
			||||||
		flags |= OSMO_SOCK_F_CONNECT;
 | 
							flags |= OSMO_SOCK_F_CONNECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
 | 
						rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
 | 
				
			||||||
				cfg->source_addr, cfg->source_port,
 | 
									cfg->source_addr, cfg->source_port,
 | 
				
			||||||
				cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
 | 
									cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,8 @@ AM_CFLAGS = \
 | 
				
			|||||||
	$(LIBOSMOVTY_CFLAGS) \
 | 
						$(LIBOSMOVTY_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMONETIF_CFLAGS) \
 | 
						$(LIBOSMONETIF_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_CFLAGS) \
 | 
				
			||||||
	$(COVERAGE_CFLAGS) \
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,6 +37,8 @@ mgcp_test_LDADD = \
 | 
				
			|||||||
	$(LIBOSMOCORE_LIBS) \
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
	$(LIBOSMOVTY_LIBS) \
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
	$(LIBOSMOGSM_LIBS) \
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOABIS_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOTRAU_LIBS) \
 | 
				
			||||||
	$(LIBRARY_DL) \
 | 
						$(LIBRARY_DL) \
 | 
				
			||||||
	$(LIBRARY_DLSYM) \
 | 
						$(LIBRARY_DLSYM) \
 | 
				
			||||||
	$(LIBOSMONETIF_LIBS) \
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,16 +22,19 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/vty.h>
 | 
					#include <osmocom/mgcp/vty.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_protocol.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_stat.h>
 | 
					#include <osmocom/mgcp/mgcp_stat.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
#include <dlfcn.h>
 | 
					#include <dlfcn.h>
 | 
				
			||||||
@@ -70,7 +73,7 @@ static void test_strline(void)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define AUEP1	"AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
 | 
					#define AUEP1	"AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
 | 
				
			||||||
#define AUEP1_RET "200 158663169 OK\r\n"
 | 
					#define AUEP1_RET "500 158663169 FAIL\r\n"
 | 
				
			||||||
#define AUEP2	"AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
 | 
					#define AUEP2	"AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
 | 
				
			||||||
#define AUEP2_RET "500 18983213 FAIL\r\n"
 | 
					#define AUEP2_RET "500 18983213 FAIL\r\n"
 | 
				
			||||||
#define EMPTY	"\r\n"
 | 
					#define EMPTY	"\r\n"
 | 
				
			||||||
@@ -81,7 +84,7 @@ static void test_strline(void)
 | 
				
			|||||||
#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
 | 
					#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
 | 
				
			||||||
#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
 | 
					#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
 | 
				
			||||||
#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
 | 
					#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
 | 
				
			||||||
#define MDCX_RET "400 18983214 FAIL\r\n"
 | 
					#define MDCX_RET "500 18983214 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX3 \
 | 
					#define MDCX3 \
 | 
				
			||||||
	"MDCX 18983215 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983215 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
@@ -591,14 +594,25 @@ static struct msgb *create_msg(const char *str, const char *conn_id)
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int last_endpoint = -1;
 | 
					static char last_endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mgcp_test_policy_cb(struct mgcp_trunk_config *cfg, int endpoint,
 | 
					static int mgcp_test_policy_cb(struct mgcp_endpoint *endp,
 | 
				
			||||||
			       int state, const char *transactio_id)
 | 
								       int state, const char *transaction_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fprintf(stderr, "Policy CB got state %d on endpoint 0x%x\n",
 | 
						unsigned int i;
 | 
				
			||||||
		state, endpoint);
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	last_endpoint = endpoint;
 | 
					
 | 
				
			||||||
 | 
						fprintf(stderr, "Policy CB got state %d on endpoint %s\n",
 | 
				
			||||||
 | 
							state, endp->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trunk = endp->trunk;
 | 
				
			||||||
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
 | 
						for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
 | 
							if (strcmp(endp->name, trunk->endpoints[i]->name) == 0)
 | 
				
			||||||
 | 
								osmo_strlcpy(last_endpoint, trunk->endpoints[i]->name,
 | 
				
			||||||
 | 
									     sizeof(last_endpoint));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return MGCP_POLICY_CONT;
 | 
						return MGCP_POLICY_CONT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -641,11 +655,11 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp)
 | 
				
			|||||||
	return real_clock_gettime(clk_id, tp);
 | 
						return real_clock_gettime(clk_id, tp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mgcp_endpoints_release(struct mgcp_trunk_config *trunk)
 | 
					static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 1; i < trunk->number_endpoints; i++)
 | 
						for (i = 0; i < trunk->number_endpoints; i++)
 | 
				
			||||||
		mgcp_endp_release(&trunk->endpoints[i]);
 | 
							mgcp_endp_release(trunk->endpoints[i]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CONN_UNMODIFIED (0x1000)
 | 
					#define CONN_UNMODIFIED (0x1000)
 | 
				
			||||||
@@ -749,23 +763,21 @@ static void test_messages(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	struct mgcp_trunk_config *trunk2;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
	char last_conn_id[256];
 | 
						char last_conn_id[256];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
						cfg->policy_cb = mgcp_test_policy_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
						memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk2 = mgcp_trunk_alloc(cfg, 1);
 | 
					 | 
				
			||||||
	mgcp_endpoints_allocate(trunk2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(tests); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(tests); i++) {
 | 
				
			||||||
		const struct mgcp_test *t = &tests[i];
 | 
							const struct mgcp_test *t = &tests[i];
 | 
				
			||||||
		struct msgb *inp;
 | 
							struct msgb *inp;
 | 
				
			||||||
@@ -774,10 +786,10 @@ static void test_messages(void)
 | 
				
			|||||||
		printf("\n================================================\n");
 | 
							printf("\n================================================\n");
 | 
				
			||||||
		printf("Testing %s\n", t->name);
 | 
							printf("Testing %s\n", t->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		last_endpoint = -1;
 | 
							last_endpoint[0] = '\0';
 | 
				
			||||||
		dummy_packets = 0;
 | 
							dummy_packets = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		osmo_talloc_replace_string(cfg, &cfg->trunk.audio_fmtp_extra,
 | 
							osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
 | 
				
			||||||
					   t->extra_fmtp);
 | 
										   t->extra_fmtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inp = create_msg(t->req, last_conn_id);
 | 
							inp = create_msg(t->req, last_conn_id);
 | 
				
			||||||
@@ -809,8 +821,9 @@ static void test_messages(void)
 | 
				
			|||||||
		if (dummy_packets)
 | 
							if (dummy_packets)
 | 
				
			||||||
			printf("Dummy packets: %d\n", dummy_packets);
 | 
								printf("Dummy packets: %d\n", dummy_packets);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (last_endpoint != -1) {
 | 
							if (last_endpoint[0] != '\0') {
 | 
				
			||||||
			endp = &cfg->trunk.endpoints[last_endpoint];
 | 
								endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
								OSMO_ASSERT(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			conn = mgcp_conn_get_rtp(endp, "1");
 | 
								conn = mgcp_conn_get_rtp(endp, "1");
 | 
				
			||||||
			if (conn) {
 | 
								if (conn) {
 | 
				
			||||||
@@ -865,10 +878,9 @@ static void test_messages(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* Check detected payload type */
 | 
							/* Check detected payload type */
 | 
				
			||||||
		if (conn && t->ptype != PTYPE_IGNORE) {
 | 
							if (conn && t->ptype != PTYPE_IGNORE) {
 | 
				
			||||||
			OSMO_ASSERT(last_endpoint != -1);
 | 
								OSMO_ASSERT(last_endpoint[0] != '\0');
 | 
				
			||||||
			endp = &cfg->trunk.endpoints[last_endpoint];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fprintf(stderr, "endpoint 0x%x: "
 | 
								fprintf(stderr, "endpoint:%s: "
 | 
				
			||||||
				"payload type %d (expected %d)\n",
 | 
									"payload type %d (expected %d)\n",
 | 
				
			||||||
				last_endpoint,
 | 
									last_endpoint,
 | 
				
			||||||
				conn->end.codec->payload_type, t->ptype);
 | 
									conn->end.codec->payload_type, t->ptype);
 | 
				
			||||||
@@ -882,29 +894,26 @@ static void test_messages(void)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(trunk2);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
					 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_retransmission(void)
 | 
					static void test_retransmission(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_trunk_config *trunk2;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	char last_conn_id[256];
 | 
						char last_conn_id[256];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
						memset(last_conn_id, 0, sizeof(last_conn_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk2 = mgcp_trunk_alloc(cfg, 1);
 | 
					 | 
				
			||||||
	mgcp_endpoints_allocate(trunk2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
 | 
				
			||||||
		const struct mgcp_test *t = &retransmit[i];
 | 
							const struct mgcp_test *t = &retransmit[i];
 | 
				
			||||||
		struct msgb *inp;
 | 
							struct msgb *inp;
 | 
				
			||||||
@@ -943,8 +952,7 @@ static void test_retransmission(void)
 | 
				
			|||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(trunk2);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
					 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -958,18 +966,16 @@ static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
 | 
				
			|||||||
static void test_rqnt_cb(void)
 | 
					static void test_rqnt_cb(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_trunk_config *trunk2;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	struct msgb *inp, *msg;
 | 
						struct msgb *inp, *msg;
 | 
				
			||||||
	char conn_id[256];
 | 
						char conn_id[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	cfg->rqnt_cb = rqnt_cb;
 | 
						cfg->rqnt_cb = rqnt_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	trunk2 = mgcp_trunk_alloc(cfg, 1);
 | 
					 | 
				
			||||||
	mgcp_endpoints_allocate(trunk2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inp = create_msg(CRCX, NULL);
 | 
						inp = create_msg(CRCX, NULL);
 | 
				
			||||||
	msg = mgcp_handle_message(cfg, inp);
 | 
						msg = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
@@ -998,8 +1004,7 @@ static void test_rqnt_cb(void)
 | 
				
			|||||||
	inp = create_msg(DLCX, conn_id);
 | 
						inp = create_msg(DLCX, conn_id);
 | 
				
			||||||
	msgb_free(mgcp_handle_message(cfg, inp));
 | 
						msgb_free(mgcp_handle_message(cfg, inp));
 | 
				
			||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	mgcp_endpoints_release(trunk2);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
					 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1035,8 +1040,9 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endpoints[1];
 | 
				
			||||||
	struct mgcp_config cfg = {0};
 | 
						struct mgcp_config cfg = {0};
 | 
				
			||||||
	struct mgcp_trunk_config trunk;
 | 
						struct mgcp_trunk trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing packet loss calculation.\n");
 | 
						printf("Testing packet loss calculation.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1045,9 +1051,10 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	endp.cfg = &cfg;
 | 
						endp.cfg = &cfg;
 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
	trunk.vty_number_endpoints = 1;
 | 
						trunk.v.vty_number_endpoints = 1;
 | 
				
			||||||
	trunk.endpoints = &endp;
 | 
						trunk.endpoints = endpoints;
 | 
				
			||||||
	endp.tcfg = &trunk;
 | 
						trunk.endpoints[0] = &endp;
 | 
				
			||||||
 | 
						endp.trunk = &trunk;
 | 
				
			||||||
	INIT_LLIST_HEAD(&endp.conns);
 | 
						INIT_LLIST_HEAD(&endp.conns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
 | 
				
			||||||
@@ -1256,19 +1263,19 @@ struct rtp_packet_info test_rtp_packets1[] = {
 | 
				
			|||||||
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
					void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
				
			||||||
			  struct mgcp_rtp_state *state,
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
			  struct mgcp_rtp_end *rtp_end,
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
			  struct sockaddr_in *addr, char *data, int len);
 | 
								  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
					static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mgcp_trunk_config trunk;
 | 
						struct mgcp_trunk trunk;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
 | 
						struct mgcp_endpoint *endpoints[1];
 | 
				
			||||||
	struct mgcp_config cfg = {0};
 | 
						struct mgcp_config cfg = {0};
 | 
				
			||||||
	struct mgcp_rtp_state state;
 | 
						struct mgcp_rtp_state state;
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
	struct sockaddr_in addr = { 0 };
 | 
						struct osmo_sockaddr addr = { 0 };
 | 
				
			||||||
	char buffer[4096];
 | 
					 | 
				
			||||||
	uint32_t last_ssrc = 0;
 | 
						uint32_t last_ssrc = 0;
 | 
				
			||||||
	uint32_t last_timestamp = 0;
 | 
						uint32_t last_timestamp = 0;
 | 
				
			||||||
	uint32_t last_seqno = 0;
 | 
						uint32_t last_seqno = 0;
 | 
				
			||||||
@@ -1295,12 +1302,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	endp.cfg = &cfg;
 | 
						endp.cfg = &cfg;
 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk.vty_number_endpoints = 1;
 | 
						trunk.v.vty_number_endpoints = 1;
 | 
				
			||||||
	trunk.endpoints = &endp;
 | 
						trunk.endpoints = endpoints;
 | 
				
			||||||
 | 
						trunk.endpoints[0] = &endp;
 | 
				
			||||||
	trunk.force_constant_ssrc = patch_ssrc;
 | 
						trunk.force_constant_ssrc = patch_ssrc;
 | 
				
			||||||
	trunk.force_aligned_timing = patch_ts;
 | 
						trunk.force_aligned_timing = patch_ts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endp.tcfg = &trunk;
 | 
						endp.trunk = &trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&endp.conns);
 | 
						INIT_LLIST_HEAD(&endp.conns);
 | 
				
			||||||
	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
						_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
@@ -1316,16 +1324,17 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
				
			||||||
		struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
							struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_alloc(4096, __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		force_monotonic_time_us = round(1000000.0 * info->txtime);
 | 
							force_monotonic_time_us = round(1000000.0 * info->txtime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		OSMO_ASSERT(info->len <= sizeof(buffer));
 | 
							OSMO_ASSERT(info->len <= msgb_tailroom(msg));
 | 
				
			||||||
		OSMO_ASSERT(info->len >= 0);
 | 
							OSMO_ASSERT(info->len >= 0);
 | 
				
			||||||
		memmove(buffer, info->data, info->len);
 | 
							msg->l3h = msgb_put(msg, info->len);
 | 
				
			||||||
 | 
							memcpy((char*)msgb_l3(msg), info->data, info->len);
 | 
				
			||||||
		mgcp_rtp_end_config(&endp, 1, rtp);
 | 
							mgcp_rtp_end_config(&endp, 1, rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgcp_patch_and_count(&endp, &state, rtp, &addr,
 | 
							mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
 | 
				
			||||||
				     buffer, info->len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (state.out_stream.ssrc != last_ssrc) {
 | 
							if (state.out_stream.ssrc != last_ssrc) {
 | 
				
			||||||
			printf("Output SSRC changed to %08x\n",
 | 
								printf("Output SSRC changed to %08x\n",
 | 
				
			||||||
@@ -1352,6 +1361,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
		last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
 | 
							last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
 | 
				
			||||||
		last_timestamp = state.out_stream.last_timestamp;
 | 
							last_timestamp = state.out_stream.last_timestamp;
 | 
				
			||||||
		last_seqno = state.out_stream.last_seq;
 | 
							last_seqno = state.out_stream.last_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	force_monotonic_time_us = -1;
 | 
						force_monotonic_time_us = -1;
 | 
				
			||||||
@@ -1361,7 +1372,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
static void test_multilple_codec(void)
 | 
					static void test_multilple_codec(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct mgcp_trunk_config *trunk2;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	struct msgb *inp, *resp;
 | 
						struct msgb *inp, *resp;
 | 
				
			||||||
	struct in_addr addr;
 | 
						struct in_addr addr;
 | 
				
			||||||
@@ -1371,15 +1382,13 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	printf("Testing multiple payload types\n");
 | 
						printf("Testing multiple payload types\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
						cfg->policy_cb = mgcp_test_policy_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk2 = mgcp_trunk_alloc(cfg, 1);
 | 
					 | 
				
			||||||
	mgcp_endpoints_allocate(trunk2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Allocate endpoint 1@mgw with two codecs */
 | 
						/* Allocate endpoint 1@mgw with two codecs */
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_1, NULL);
 | 
						inp = create_msg(CRCX_MULT_1, NULL);
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
@@ -1387,14 +1396,15 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 1);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 2@mgw with three codecs, last one ignored */
 | 
						/* Allocate 2@mgw with three codecs, last one ignored */
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_2, NULL);
 | 
						inp = create_msg(CRCX_MULT_2, NULL);
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
@@ -1402,8 +1412,9 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 2);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
				
			||||||
@@ -1414,7 +1425,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	 * it makes and since we already decided in OS#2658 that a missing
 | 
						 * it makes and since we already decided in OS#2658 that a missing
 | 
				
			||||||
	 * LCO should pick a sane default codec, it makes sense to expect
 | 
						 * LCO should pick a sane default codec, it makes sense to expect
 | 
				
			||||||
	 * the same behaviour if SDP lacks proper payload type information */
 | 
						 * the same behaviour if SDP lacks proper payload type information */
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_3, NULL);
 | 
						inp = create_msg(CRCX_MULT_3, NULL);
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
@@ -1422,14 +1433,15 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 3);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 4@mgw with a single codec */
 | 
						/* Allocate 4@mgw with a single codec */
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_4, NULL);
 | 
						inp = create_msg(CRCX_MULT_4, NULL);
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
@@ -1437,44 +1449,46 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 4);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 18);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Allocate 5@mgw at select GSM.. */
 | 
						/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
				
			||||||
	talloc_free(cfg->trunk.audio_name);
 | 
						trunk->no_audio_transcoding = 1;
 | 
				
			||||||
	cfg->trunk.audio_name = "GSM/8000";
 | 
					 | 
				
			||||||
	cfg->trunk.no_audio_transcoding = 1;
 | 
					 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
					      sizeof(conn_id)) == 0);
 | 
										      sizeof(conn_id)) == 0);
 | 
				
			||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 5);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inp = create_msg(MDCX_NAT_DUMMY, conn_id);
 | 
						inp = create_msg(MDCX_NAT_DUMMY, conn_id);
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 5);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.rtp_port == htons(16434));
 | 
						OSMO_ASSERT(conn->end.rtp_port == htons(16434));
 | 
				
			||||||
	memset(&addr, 0, sizeof(addr));
 | 
						memset(&addr, 0, sizeof(addr));
 | 
				
			||||||
	inet_aton("8.8.8.8", &addr);
 | 
						inet_aton("8.8.8.8", &addr);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.addr.s_addr == addr.s_addr);
 | 
						OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
 | 
				
			||||||
 | 
						OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check what happens without that flag */
 | 
						/* Check what happens without that flag */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1487,23 +1501,23 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(!conn);
 | 
						OSMO_ASSERT(!conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	last_endpoint = -1;
 | 
						last_endpoint[0] = '\0';
 | 
				
			||||||
	inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
						inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
 | 
				
			||||||
	cfg->trunk.no_audio_transcoding = 0;
 | 
						trunk->no_audio_transcoding = 0;
 | 
				
			||||||
	resp = mgcp_handle_message(cfg, inp);
 | 
						resp = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
	OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
						OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
 | 
				
			||||||
					      sizeof(conn_id)) == 0);
 | 
										      sizeof(conn_id)) == 0);
 | 
				
			||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(resp);
 | 
						msgb_free(resp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(last_endpoint == 5);
 | 
						OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[last_endpoint];
 | 
						endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(trunk2);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
					 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1513,14 +1527,17 @@ static void test_no_cycle(void)
 | 
				
			|||||||
	struct mgcp_endpoint *endp;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
	struct mgcp_conn *_conn = NULL;
 | 
						struct mgcp_conn *_conn = NULL;
 | 
				
			||||||
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing no sequence flow on initial packet\n");
 | 
						printf("Testing no sequence flow on initial packet\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endp = &cfg->trunk.endpoints[1];
 | 
						endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
 | 
				
			||||||
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
 | 
						_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
 | 
				
			||||||
				"test-connection");
 | 
									"test-connection");
 | 
				
			||||||
@@ -1552,28 +1569,26 @@ static void test_no_cycle(void)
 | 
				
			|||||||
	OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
 | 
						OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
 | 
				
			||||||
	OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
						OSMO_ASSERT(conn->state.stats.max_seq == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_no_name(void)
 | 
					static void test_no_name(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *trunk2;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
	struct mgcp_config *cfg;
 | 
						struct mgcp_config *cfg;
 | 
				
			||||||
	struct msgb *inp, *msg;
 | 
						struct msgb *inp, *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing no rtpmap name\n");
 | 
						printf("Testing no rtpmap name\n");
 | 
				
			||||||
	cfg = mgcp_config_alloc();
 | 
						cfg = mgcp_config_alloc();
 | 
				
			||||||
 | 
						trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->trunk.vty_number_endpoints = 64;
 | 
						trunk->v.vty_number_endpoints = 64;
 | 
				
			||||||
	cfg->trunk.audio_send_name = 0;
 | 
						trunk->audio_send_name = 0;
 | 
				
			||||||
	mgcp_endpoints_allocate(&cfg->trunk);
 | 
					        mgcp_trunk_equip(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->policy_cb = mgcp_test_policy_cb;
 | 
						cfg->policy_cb = mgcp_test_policy_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk2 = mgcp_trunk_alloc(cfg, 1);
 | 
					 | 
				
			||||||
	mgcp_endpoints_allocate(trunk2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inp = create_msg(CRCX, NULL);
 | 
						inp = create_msg(CRCX, NULL);
 | 
				
			||||||
	msg = mgcp_handle_message(cfg, inp);
 | 
						msg = mgcp_handle_message(cfg, inp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1585,8 +1600,7 @@ static void test_no_name(void)
 | 
				
			|||||||
	msgb_free(inp);
 | 
						msgb_free(inp);
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_endpoints_release(trunk2);
 | 
						mgcp_endpoints_release(trunk);
 | 
				
			||||||
	mgcp_endpoints_release(&cfg->trunk);
 | 
					 | 
				
			||||||
	talloc_free(cfg);
 | 
						talloc_free(cfg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2105,6 +2119,48 @@ void test_conn_id_matching()
 | 
				
			|||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_e1_trunk_nr_from_epname()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int trunk_nr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note: e1_trunk_nr_from_epname does not check the text
 | 
				
			||||||
 | 
						 * after the E1 trunk number, after the delimiter
 | 
				
			||||||
 | 
						 * character "/" arbitrary text may follow. */
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 0);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 1);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 2);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 3);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 3);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 24);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The following endpoint strings should fail, either the
 | 
				
			||||||
 | 
						 * trunk number exceeds the valid range or the trunk prefix
 | 
				
			||||||
 | 
						 * is wrong. Also when the delimiter character "/" at the
 | 
				
			||||||
 | 
						 * end of the trunk is wrong the parsing should fail. */
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
						trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
 | 
				
			||||||
 | 
						OSMO_ASSERT(trunk_nr == -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
 | 
						void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
 | 
				
			||||||
@@ -2130,6 +2186,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_check_local_cx_options(ctx);
 | 
						test_check_local_cx_options(ctx);
 | 
				
			||||||
	test_mgcp_codec_pt_translate();
 | 
						test_mgcp_codec_pt_translate();
 | 
				
			||||||
	test_conn_id_matching();
 | 
						test_conn_id_matching();
 | 
				
			||||||
 | 
						test_e1_trunk_nr_from_epname();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
 | 
						OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
 | 
				
			||||||
	OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
 | 
						OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -294,11 +294,23 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
	     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
	memset(audio_ip_overflow, 'X', sizeof(audio_ip_overflow));
 | 
						memset(audio_ip_overflow, 'X', sizeof(audio_ip_overflow));
 | 
				
			||||||
 | 
						audio_ip_overflow[1] = '.';
 | 
				
			||||||
	audio_ip_overflow[sizeof(audio_ip_overflow) - 1] = '\0';
 | 
						audio_ip_overflow[sizeof(audio_ip_overflow) - 1] = '\0';
 | 
				
			||||||
	mgcp_msg.audio_ip = audio_ip_overflow;
 | 
						mgcp_msg.audio_ip = audio_ip_overflow;
 | 
				
			||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	OSMO_ASSERT(msg == NULL);
 | 
						OSMO_ASSERT(msg == NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("IPv6 test:\n");
 | 
				
			||||||
 | 
						mgcp_msg.verb = MGCP_VERB_MDCX;
 | 
				
			||||||
 | 
						mgcp_msg.presence =
 | 
				
			||||||
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
 | 
				
			||||||
 | 
						     MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
 | 
				
			||||||
 | 
						mgcp_msg.audio_ip = "2001:db8:1::ab9:c0a8:102";
 | 
				
			||||||
 | 
						mgcp->actual.remote_addr = "::1";
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\n");
 | 
						printf("\n");
 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -413,6 +425,66 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
 | 
				
			|||||||
			"m=audio 23\r\n",
 | 
								"m=audio 23\r\n",
 | 
				
			||||||
		.expect_rc = 0,
 | 
							.expect_rc = 0,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4\r\n",
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_ip = "1.2.3.4",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP6 2001:db8:1::ab9:c0a8:102\r\n",
 | 
				
			||||||
 | 
							.expect_params = {
 | 
				
			||||||
 | 
								.audio_ip = "2001:db8:1::ab9:c0a8:102",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect_rc = 0,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP6 1.2.3.4\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 ::1\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 notanip\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2.3.4.5.6\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2 .3\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 1.2 .3\r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.body = "some mgcp header data\r\nand header params"
 | 
				
			||||||
 | 
								"\r\n\r\n"
 | 
				
			||||||
 | 
								"c=IN IP4 \r\n",
 | 
				
			||||||
 | 
							.expect_rc = -22,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_sdp_section_start()
 | 
					void test_sdp_section_start()
 | 
				
			||||||
@@ -443,7 +515,12 @@ void test_sdp_section_start()
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fprintf(stderr, "got audio_port=%u\n", t->expect_params.audio_port);
 | 
							fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
 | 
				
			||||||
 | 
							if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
 | 
				
			||||||
 | 
								fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
 | 
				
			||||||
 | 
								failures++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fprintf(stderr, "got audio_port=%u\n", r->audio_port);
 | 
				
			||||||
		if (r->audio_port != t->expect_params.audio_port) {
 | 
							if (r->audio_port != t->expect_params.audio_port) {
 | 
				
			||||||
			fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
 | 
								fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
 | 
				
			||||||
			failures++;
 | 
								failures++;
 | 
				
			||||||
@@ -547,6 +624,57 @@ static void test_map_codec_to_pt_and_map_pt_to_codec(void)
 | 
				
			|||||||
	printf("\n");
 | 
						printf("\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_mgcp_client_e1_epname(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *epname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp)
 | 
				
			||||||
 | 
							talloc_free(mgcp);
 | 
				
			||||||
 | 
						mgcp = mgcp_client_init(ctx, &conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Valid endpoint names */
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 2, 14, 32, 0);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 3, 13, 32, 4);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 4, 12, 16, 0);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 5, 11, 16, 2);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 6, 10, 16, 4);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 7, 9, 16, 6);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 8, 8, 8, 0);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 9, 7, 8, 1);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 10, 6, 8, 2);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 11, 5, 8, 3);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 12, 4, 8, 4);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 13, 3, 8, 5);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 14, 2, 8, 6);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 7);
 | 
				
			||||||
 | 
						printf("%s\n", epname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A few invalid enpoint names */
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 128, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 16);
 | 
				
			||||||
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 0, 8, 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
 | 
						epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 64, 8, 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(epname == NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat log_categories[] = {
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -575,6 +703,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_sdp_section_start();
 | 
						test_sdp_section_start();
 | 
				
			||||||
	test_map_codec_to_pt_and_map_pt_to_codec();
 | 
						test_map_codec_to_pt_and_map_pt_to_codec();
 | 
				
			||||||
	test_map_pt_to_codec();
 | 
						test_map_pt_to_codec();
 | 
				
			||||||
 | 
						test_mgcp_client_e1_epname();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Done\n");
 | 
						printf("Done\n");
 | 
				
			||||||
	fprintf(stderr, "Done\n");
 | 
						fprintf(stderr, "Done\n");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,57 +19,119 @@ test_sdp_section_start() test [0]:
 | 
				
			|||||||
body: ""
 | 
					body: ""
 | 
				
			||||||
DLMGCP MGCP response contains no SDP parameters
 | 
					DLMGCP MGCP response contains no SDP parameters
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [1]:
 | 
					test_sdp_section_start() test [1]:
 | 
				
			||||||
body: "\n\n"
 | 
					body: "\n\n"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [2]:
 | 
					test_sdp_section_start() test [2]:
 | 
				
			||||||
body: "\r\n\r\n"
 | 
					body: "\r\n\r\n"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [3]:
 | 
					test_sdp_section_start() test [3]:
 | 
				
			||||||
body: "\n\r\n\r"
 | 
					body: "\n\r\n\r"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [4]:
 | 
					test_sdp_section_start() test [4]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\n\nm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\n\nm=audio 23\r\n"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=23
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [5]:
 | 
					test_sdp_section_start() test [5]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\r\n\r\nm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nm=audio 23\r\n"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=23
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [6]:
 | 
					test_sdp_section_start() test [6]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\n\r\n\rm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\n\r\n\rm=audio 23\r\n"
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=23
 | 
					got audio_port=23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [7]:
 | 
					test_sdp_section_start() test [7]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\n\r\nm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\n\r\nm=audio 23\r\n"
 | 
				
			||||||
DLMGCP MGCP response contains no SDP parameters
 | 
					DLMGCP MGCP response contains no SDP parameters
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [8]:
 | 
					test_sdp_section_start() test [8]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\r\n\rm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\r\n\rm=audio 23\r\n"
 | 
				
			||||||
DLMGCP MGCP response contains no SDP parameters
 | 
					DLMGCP MGCP response contains no SDP parameters
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [9]:
 | 
					test_sdp_section_start() test [9]:
 | 
				
			||||||
body: "some mgcp header data\r\nand header params\n\r\rm=audio 23\r\n"
 | 
					body: "some mgcp header data\r\nand header params\n\r\rm=audio 23\r\n"
 | 
				
			||||||
DLMGCP MGCP response contains no SDP parameters
 | 
					DLMGCP MGCP response contains no SDP parameters
 | 
				
			||||||
got rc=0
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip=""
 | 
				
			||||||
got audio_port=0
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [10]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="1.2.3.4"
 | 
				
			||||||
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [11]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 2001:db8:1::ab9:c0a8:102\r\n"
 | 
				
			||||||
 | 
					got rc=0
 | 
				
			||||||
 | 
					got audio_ip="2001:db8:1::ab9:c0a8:102"
 | 
				
			||||||
 | 
					got audio_port=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [12]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 1.2.3.4\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [13]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 ::1\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [14]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 notanip\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [15]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4.5.6\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [16]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [17]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [18]:
 | 
				
			||||||
 | 
					body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 \r\n"
 | 
				
			||||||
 | 
					DLMGCP Failed to parse MGCP response header (audio ip)
 | 
				
			||||||
 | 
					got rc=-22
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
					DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
					DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
					DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
 | 
				
			||||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
					DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
 | 
				
			||||||
 | 
					DLMGCP MGCP client: using endpoint domain '@mgw'
 | 
				
			||||||
 | 
					DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
 | 
				
			||||||
 | 
					DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
 | 
				
			||||||
 | 
					DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
 | 
				
			||||||
 | 
					DLMGCP Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
 | 
				
			||||||
Done
 | 
					Done
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,6 +109,20 @@ M: sendrecv
 | 
				
			|||||||
X-Osmux: 2
 | 
					X-Osmux: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Overfolow test:
 | 
					Overfolow test:
 | 
				
			||||||
 | 
					IPv6 test:
 | 
				
			||||||
 | 
					MDCX 19 23@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2f
 | 
				
			||||||
 | 
					I: 11
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					o=- 2f 23 IN IP6 ::1
 | 
				
			||||||
 | 
					s=-
 | 
				
			||||||
 | 
					c=IN IP6 2001:db8:1::ab9:c0a8:102
 | 
				
			||||||
 | 
					t=0 0
 | 
				
			||||||
 | 
					m=audio 1234 RTP/AVP 3
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_mgcp_client_cancel():
 | 
					test_mgcp_client_cancel():
 | 
				
			||||||
@@ -149,6 +163,24 @@ test_sdp_section_start() test [7]:
 | 
				
			|||||||
test_sdp_section_start() test [8]:
 | 
					test_sdp_section_start() test [8]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_sdp_section_start() test [9]:
 | 
					test_sdp_section_start() test [9]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [10]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [11]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [12]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [13]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [14]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [15]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [16]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [17]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_sdp_section_start() test [18]:
 | 
				
			||||||
 110 => 96
 | 
					 110 => 96
 | 
				
			||||||
 111 => 97
 | 
					 111 => 97
 | 
				
			||||||
 112 => 98
 | 
					 112 => 98
 | 
				
			||||||
@@ -178,4 +210,19 @@ test_sdp_section_start() test [9]:
 | 
				
			|||||||
 2 <= 2
 | 
					 2 <= 2
 | 
				
			||||||
 100 <= 100
 | 
					 100 <= 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ds/e1-1/s-15/su64-0@mgw
 | 
				
			||||||
 | 
					ds/e1-2/s-14/su32-0@mgw
 | 
				
			||||||
 | 
					ds/e1-3/s-13/su32-4@mgw
 | 
				
			||||||
 | 
					ds/e1-4/s-12/su16-0@mgw
 | 
				
			||||||
 | 
					ds/e1-5/s-11/su16-2@mgw
 | 
				
			||||||
 | 
					ds/e1-6/s-10/su16-4@mgw
 | 
				
			||||||
 | 
					ds/e1-7/s-9/su16-6@mgw
 | 
				
			||||||
 | 
					ds/e1-8/s-8/su8-0@mgw
 | 
				
			||||||
 | 
					ds/e1-9/s-7/su8-1@mgw
 | 
				
			||||||
 | 
					ds/e1-10/s-6/su8-2@mgw
 | 
				
			||||||
 | 
					ds/e1-11/s-5/su8-3@mgw
 | 
				
			||||||
 | 
					ds/e1-12/s-4/su8-4@mgw
 | 
				
			||||||
 | 
					ds/e1-13/s-3/su8-5@mgw
 | 
				
			||||||
 | 
					ds/e1-14/s-2/su8-6@mgw
 | 
				
			||||||
 | 
					ds/e1-15/s-1/su8-7@mgw
 | 
				
			||||||
Done
 | 
					Done
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user