mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			122 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					51565999da | ||
| 
						 | 
					fb8624ed1e | ||
| 
						 | 
					1d23dfb0aa | ||
| 
						 | 
					6087326beb | ||
| 
						 | 
					342a9a9418 | ||
| 
						 | 
					22f9cf2687 | ||
| 
						 | 
					26d6b2b5ce | ||
| 
						 | 
					169d50ed4a | ||
| 
						 | 
					82dfb505db | ||
| 
						 | 
					9c0d105d09 | ||
| 
						 | 
					ded02cfc29 | ||
| 
						 | 
					0cbed362cd | ||
| 
						 | 
					310e41cdf3 | ||
| 
						 | 
					a55bfdc436 | ||
| 
						 | 
					6ea8d7dac6 | ||
| 
						 | 
					9befdeb673 | ||
| 
						 | 
					5fb814b6b9 | ||
| 
						 | 
					9ac9cb963d | ||
| 
						 | 
					377d39122d | ||
| 
						 | 
					d1e94c7ac3 | ||
| 
						 | 
					6db3f7f1cb | ||
| 
						 | 
					58c0b0a6f7 | ||
| 
						 | 
					cca55247ed | ||
| 
						 | 
					d266c374ee | ||
| 
						 | 
					d358d71206 | ||
| 
						 | 
					5e6661eece | ||
| 
						 | 
					c1468ef7a5 | ||
| 
						 | 
					24763eaa73 | ||
| 
						 | 
					d8c2f31a87 | ||
| 
						 | 
					01b812ea76 | ||
| 
						 | 
					0807771b9e | ||
| 
						 | 
					103e50a561 | ||
| 
						 | 
					3a914e33e9 | ||
| 
						 | 
					2172f402a5 | ||
| 
						 | 
					8c138fe89c | ||
| 
						 | 
					7881f7da0b | ||
| 
						 | 
					d17a9de79e | ||
| 
						 | 
					8e74c63e15 | ||
| 
						 | 
					80dd576ad2 | ||
| 
						 | 
					cb922b646f | ||
| 
						 | 
					5d8b5b0935 | ||
| 
						 | 
					35bd2523e2 | ||
| 
						 | 
					f45a9b9760 | ||
| 
						 | 
					f48cd95bbc | ||
| 
						 | 
					7558c20973 | ||
| 
						 | 
					6ddc79b6ed | ||
| 
						 | 
					ff5921573a | ||
| 
						 | 
					d4ad77d326 | ||
| 
						 | 
					a6917fecb1 | ||
| 
						 | 
					58877f04e3 | ||
| 
						 | 
					d4707e2185 | ||
| 
						 | 
					f633302c73 | ||
| 
						 | 
					36413c011f | ||
| 
						 | 
					833281dcb9 | ||
| 
						 | 
					07bbd766c5 | ||
| 
						 | 
					c7c8e649f1 | ||
| 
						 | 
					c0e1b1aec5 | ||
| 
						 | 
					9735d21b9d | ||
| 
						 | 
					705565d745 | ||
| 
						 | 
					63088e0e61 | ||
| 
						 | 
					887c93e198 | ||
| 
						 | 
					2ca48823b1 | ||
| 
						 | 
					e7de137b29 | ||
| 
						 | 
					c1ad7fd92b | ||
| 
						 | 
					3779919551 | ||
| 
						 | 
					8e0d101997 | ||
| 
						 | 
					654b68d602 | ||
| 
						 | 
					70c03f5e44 | ||
| 
						 | 
					e56ec4a146 | ||
| 
						 | 
					5ffd127384 | ||
| 
						 | 
					051eb4d563 | ||
| 
						 | 
					e740665cab | ||
| 
						 | 
					abb9d47c90 | ||
| 
						 | 
					2dd2b33030 | ||
| 
						 | 
					69f15e4e95 | ||
| 
						 | 
					b0ea7976bf | ||
| 
						 | 
					9d939b6d5d | ||
| 
						 | 
					de805b6772 | ||
| 
						 | 
					cb25a0aa48 | ||
| 
						 | 
					72eff2cf6a | ||
| 
						 | 
					1c5fcb0791 | ||
| 
						 | 
					48fb176fbc | ||
| 
						 | 
					4d090d85f4 | ||
| 
						 | 
					81c5847434 | ||
| 
						 | 
					d48a811f6c | ||
| 
						 | 
					b7f52b414e | ||
| 
						 | 
					ea7aaf2eca | ||
| 
						 | 
					432ee9d150 | ||
| 
						 | 
					b4a59475d2 | ||
| 
						 | 
					2177919edb | ||
| 
						 | 
					87f114a1d0 | ||
| 
						 | 
					928a20b540 | ||
| 
						 | 
					b9022497d8 | ||
| 
						 | 
					582c2bf7b0 | ||
| 
						 | 
					663ba5c41f | ||
| 
						 | 
					daf5bcea99 | ||
| 
						 | 
					a29f155301 | ||
| 
						 | 
					941e317c97 | ||
| 
						 | 
					3fbf035923 | ||
| 
						 | 
					21bcf6abd8 | ||
| 
						 | 
					26e810d8a9 | ||
| 
						 | 
					4d1a52d463 | ||
| 
						 | 
					83df47cd7a | ||
| 
						 | 
					c5bbb78ffe | ||
| 
						 | 
					e0e5a772f4 | ||
| 
						 | 
					e39ae87ea3 | ||
| 
						 | 
					8b0a614e43 | ||
| 
						 | 
					c61664c2b2 | ||
| 
						 | 
					15e7e4f37d | ||
| 
						 | 
					ab8371c6d7 | ||
| 
						 | 
					8c777990a5 | ||
| 
						 | 
					ec5e85b84e | ||
| 
						 | 
					ab4e8663e1 | ||
| 
						 | 
					a4f783b51b | ||
| 
						 | 
					479cf76e55 | ||
| 
						 | 
					33639166a2 | ||
| 
						 | 
					709aad28ed | ||
| 
						 | 
					5892b2e4db | ||
| 
						 | 
					f1f73b8e1d | ||
| 
						 | 
					0fdc08c551 | ||
| 
						 | 
					5be57da075 | ||
| 
						 | 
					147184eb06 | 
							
								
								
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							@@ -44,13 +44,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.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.3.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.4.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.4.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS="$CFLAGS -pthread"
 | 
					CFLAGS="$CFLAGS -pthread"
 | 
				
			||||||
LDFLAGS="$LDFLAGS -pthread"
 | 
					LDFLAGS="$LDFLAGS -pthread"
 | 
				
			||||||
@@ -79,6 +79,7 @@ AC_ARG_ENABLE(werror,
 | 
				
			|||||||
if test x"$werror" = x"yes"
 | 
					if test x"$werror" = x"yes"
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	WERROR_FLAGS="-Werror"
 | 
						WERROR_FLAGS="-Werror"
 | 
				
			||||||
 | 
						WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
						WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
						WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
				
			||||||
	CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
						CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,30 +29,30 @@ BuildRequires:  pkgconfig >= 0.20
 | 
				
			|||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
%endif
 | 
					%endif
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.2.0
 | 
					BuildRequires:  pkgconfig(libosmo-netif) >= 1.3.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmogsm) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmocoding) >= 1.8.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.3.0
 | 
					BuildRequires:  pkgconfig(libosmoabis) >= 1.4.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.3.0
 | 
					BuildRequires:  pkgconfig(libosmotrau) >= 1.4.0
 | 
				
			||||||
%{?systemd_requires}
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description
 | 
					%description
 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client9
 | 
					%package -n libosmo-mgcp-client11
 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          System/Libraries
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client9
 | 
					%description -n libosmo-mgcp-client11
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					Osmocom's Media Gateway Control Protocol client library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					%package -n libosmo-mgcp-client-devel
 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					Group:          Development/Libraries/C and C++
 | 
				
			||||||
Requires:       libosmo-mgcp-client9 = %{version}
 | 
					Requires:       libosmo-mgcp-client11 = %{version}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					%description -n libosmo-mgcp-client-devel
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					Osmocom's Media Gateway Control Protocol client librarary.
 | 
				
			||||||
@@ -90,8 +90,8 @@ find %{buildroot} -type f -name "*.la" -delete -print
 | 
				
			|||||||
%check
 | 
					%check
 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%post   -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
					%post   -n libosmo-mgcp-client11 -p /sbin/ldconfig
 | 
				
			||||||
%postun -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
					%postun -n libosmo-mgcp-client11 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
%preun
 | 
					%preun
 | 
				
			||||||
@@ -119,8 +119,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
%dir %{_sysconfdir}/osmocom
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client9
 | 
					%files -n libosmo-mgcp-client11
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.9*
 | 
					%{_libdir}/libosmo-mgcp-client.so.11*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					%files -n libosmo-mgcp-client-devel
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					%{_libdir}/libosmo-mgcp-client.so
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,20 @@
 | 
				
			|||||||
[Unit]
 | 
					[Unit]
 | 
				
			||||||
Description=Osmocom Media Gateway (MGW)
 | 
					Description=Osmocom Media Gateway (MGW)
 | 
				
			||||||
 | 
					After=network-online.target
 | 
				
			||||||
 | 
					Wants=network-online.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Service]
 | 
					[Service]
 | 
				
			||||||
Type=simple
 | 
					Type=simple
 | 
				
			||||||
 | 
					StateDirectory=osmocom
 | 
				
			||||||
 | 
					WorkingDirectory=%S/osmocom
 | 
				
			||||||
Restart=always
 | 
					Restart=always
 | 
				
			||||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
					ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
RestartSec=2
 | 
					RestartSec=2
 | 
				
			||||||
 | 
					# CPU scheduling policy:
 | 
				
			||||||
 | 
					CPUSchedulingPolicy=rr
 | 
				
			||||||
 | 
					# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
 | 
				
			||||||
 | 
					CPUSchedulingPriority=1
 | 
				
			||||||
 | 
					# See sched(7) for further details on real-time policies and priorities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Install]
 | 
					[Install]
 | 
				
			||||||
WantedBy=multi-user.target
 | 
					WantedBy=multi-user.target
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										145
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										145
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +1,149 @@
 | 
				
			|||||||
osmo-mgw (1.10.1) unstable; urgency=medium
 | 
					osmo-mgw (1.11.2) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * systemd: depend on networking-online.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Oliver Smith <osmith@sysmocom.de>  Fri, 26 May 2023 17:49:29 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.11.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * mgcp_network: Unregister osmo_fd before closing fd
 | 
					  * mgcp_network: Unregister osmo_fd before closing fd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Fri, 10 Mar 2023 16:04:04 +0100
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Fri, 10 Mar 2023 14:55:21 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-mgw (1.11.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp-client: Remove impossible code path
 | 
				
			||||||
 | 
					  * mgcp_osmux: Drop duplicated conn_osmux_release_cid() in code path
 | 
				
			||||||
 | 
					  * Use Osmux default port define from libosmo-netif
 | 
				
			||||||
 | 
					  * osmux: Use new osmux APIs to let libosmo-netif alloc struct osmux_out_handle
 | 
				
			||||||
 | 
					  * mgw: Fix osmux conn local IP selection
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Fix wrong indentation
 | 
				
			||||||
 | 
					  * mgw: Use X-Osmux string define
 | 
				
			||||||
 | 
					  * Add Osmux log category
 | 
				
			||||||
 | 
					  * cosmetic: main: Properly format log_info_cat
 | 
				
			||||||
 | 
					  * osmux: Use better name for function which may allocate a new struct
 | 
				
			||||||
 | 
					  * osmux: Use osmo_sockaddr wherever possible
 | 
				
			||||||
 | 
					  * osmux: Log refcounting of osmux_handle_list
 | 
				
			||||||
 | 
					  * osmux: Fix memleak on error code path
 | 
				
			||||||
 | 
					  * osmux: don't store conn ptr inside shared osmux_handle
 | 
				
			||||||
 | 
					  * osmux: set log level of expected code path to INFO
 | 
				
			||||||
 | 
					  * cosmetic: vty: Fix indentation whitespace
 | 
				
			||||||
 | 
					  * osmux: Log sendto() error
 | 
				
			||||||
 | 
					  * cosmetic: mgcp_conn.h: fix indentation whitespace
 | 
				
			||||||
 | 
					  * osmux: Attach osmux to virtual trunk
 | 
				
			||||||
 | 
					  * osmux: Clean up helper macro osmux_chunk_length()
 | 
				
			||||||
 | 
					  * osmux: Get rid of static NULL talloc context
 | 
				
			||||||
 | 
					  * Fix typo in ratectr description
 | 
				
			||||||
 | 
					  * mgcp_conn: rename field s/rate_ctr_group/ctrg/g
 | 
				
			||||||
 | 
					  * Use 'static const' instead of 'const static' everywhere
 | 
				
			||||||
 | 
					  * osmux: Add connection and global rate counters
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Fix formatting of if-else brackets
 | 
				
			||||||
 | 
					  * osmux: Rename field osmux usage policy and define it with proper type
 | 
				
			||||||
 | 
					  * Use bool type instead of int in config field
 | 
				
			||||||
 | 
					  * osmux: Support local CID != remote CID
 | 
				
			||||||
 | 
					  * osmux: Fix incorrect rate_ctr_group used in mgcp_osmux.c
 | 
				
			||||||
 | 
					  * osmux: Improve per-conn tx rate counters
 | 
				
			||||||
 | 
					  * vty: show per-connection Osmux VTY stats
 | 
				
			||||||
 | 
					  * osmux: Rename field s/init/initialized
 | 
				
			||||||
 | 
					  * osmux: Allocate rate counters during initialization of osmux conn
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Drop extra empty line
 | 
				
			||||||
 | 
					  * osmux: Drop unneeded comment block
 | 
				
			||||||
 | 
					  * osmux: Lower log level when osmux batch received for unknown CID
 | 
				
			||||||
 | 
					  * osmux: Keep decoding osmux pkt if a batch contains an unknown CID
 | 
				
			||||||
 | 
					  * Allocate struct osmux_in_handle through new libosmo-netif APIs
 | 
				
			||||||
 | 
					  * osmux: Drop logging of osmux internal counters
 | 
				
			||||||
 | 
					  * osmux: cleanup misleading code calling rtp_bridge_cb
 | 
				
			||||||
 | 
					  * osmux: Unify rtp_conn osmux type into a single type
 | 
				
			||||||
 | 
					  * osmux: Match remote address in osmux_conn_lookup()
 | 
				
			||||||
 | 
					  * osmux: Fill in from_addr in struct osmo_rtp_msg_ctx
 | 
				
			||||||
 | 
					  * osmux: Log remote address upon rx of osmux pkt
 | 
				
			||||||
 | 
					  * send_dummy: Use proper condition to test if conn is osmux
 | 
				
			||||||
 | 
					  * Fix regression in detection of legacy dummy packets
 | 
				
			||||||
 | 
					  * Use new libosmocore API osmo_sockaddr_is_any()
 | 
				
			||||||
 | 
					  * Get rid of separate rtp_port field
 | 
				
			||||||
 | 
					  * osmux: Use available API to check if remote end is known
 | 
				
			||||||
 | 
					  * Add Osmux IPv6 support
 | 
				
			||||||
 | 
					  * Clean up local var pointers in mgcp_get_local_addr()
 | 
				
			||||||
 | 
					  * osmux: Change couple log lines to OSMUX category
 | 
				
			||||||
 | 
					  * osmux: Add square brackets around IPv6 address to distinguish port in log line
 | 
				
			||||||
 | 
					  * osmux: Drop unused role parameter
 | 
				
			||||||
 | 
					  * osmux: cosmetic: Fix indentation
 | 
				
			||||||
 | 
					  * Check once if remote addr is available when sending dummy packet
 | 
				
			||||||
 | 
					  * osmux: Simplify and constify param passing
 | 
				
			||||||
 | 
					  * osmux: Set conn->type during osmux_init_conn()
 | 
				
			||||||
 | 
					  * osmux: Make conn_osmux_{allocate,release}_local_cid() APIs static
 | 
				
			||||||
 | 
					  * osmux: Define osmux_dummy cfg as boolean
 | 
				
			||||||
 | 
					  * osmux: Move setting OSMUX_STATE_DISABLED to initializer function
 | 
				
			||||||
 | 
					  * osmux: Erase references to bsc-nat
 | 
				
			||||||
 | 
					  * mgcp_conn_dump(): Separate dump for osmux and iuup connections
 | 
				
			||||||
 | 
					  * osmux: Introduce osmux peer-behind-nat (on|off) and rework conn activation
 | 
				
			||||||
 | 
					  * osmux: Clean up mgcp_config osmux fields
 | 
				
			||||||
 | 
					  * cosmetic: Fix typo in comment
 | 
				
			||||||
 | 
					  * mgcp-client: pool: Improve documentation of some internal fields
 | 
				
			||||||
 | 
					  * mgcp-client: Avoid double iteration picking client from pool
 | 
				
			||||||
 | 
					  * mgcp-client: Fix typo in internal function name
 | 
				
			||||||
 | 
					  * mgcp-client: Rename internal field in mgcp_client_pool
 | 
				
			||||||
 | 
					  * mgcp-client: Move & rename helper function outside of vty code
 | 
				
			||||||
 | 
					  * mgcp-client: Create alloc() and free() internal APIs for mgcp_client_pool_member
 | 
				
			||||||
 | 
					  * mgcp-client: Move internal API acting on mgcp_client_pool to the correct file section
 | 
				
			||||||
 | 
					  * mgcp-client: Refactor reinit of mgcp clients
 | 
				
			||||||
 | 
					  * mgcp-client: Rearrange order of structs and APIs in header
 | 
				
			||||||
 | 
					  * mgcp-client: Rearrange internal backpointers
 | 
				
			||||||
 | 
					  * mgcp-client: Introduce APIs to manually select mgcp_client from pool
 | 
				
			||||||
 | 
					  * mgcp-client: vty: Write deprecation warning using non-mgw nodes
 | 
				
			||||||
 | 
					  * mgcp-client: Use random free local port by default
 | 
				
			||||||
 | 
					  * mgcp-client: Convert users supporting new MGW Pool VTY node during write-config
 | 
				
			||||||
 | 
					  * mgcp-client: Introduce API mgcp_client_pool_config_write
 | 
				
			||||||
 | 
					  * mgcp-client: Add new VTY commands under mgw node without mgw prefix
 | 
				
			||||||
 | 
					  * mgcp-client: Fix 'mgw endpoint-range' command dropped from old VTY node
 | 
				
			||||||
 | 
					  * mgcp-client: Refactor system keeping old users not calling mgcp_client_pool_config_write() working
 | 
				
			||||||
 | 
					  * mgcp-client: Fix no 'mgw ' prefix written in old VTY node
 | 
				
			||||||
 | 
					  * Fix misleading error log
 | 
				
			||||||
 | 
					  * mgcp_send: Use mgcp_conn_rtp_is_iuup() helper
 | 
				
			||||||
 | 
					  * cosmetic: Clarify and fix typos in comment
 | 
				
			||||||
 | 
					  * mgw: Log unexpected RTP AMR OA-vs-BE payload
 | 
				
			||||||
 | 
					  * Rename and move func checking if amr mode is explicitly configured
 | 
				
			||||||
 | 
					  * mgw: rx_rtp(): reorder checks and handlings
 | 
				
			||||||
 | 
					  * mgw: Rename s/mgcp_send_rtp/mgcp_conn_rtp_dispatch_rtp/
 | 
				
			||||||
 | 
					  * osmux: Rename function and pass msgb directly to it
 | 
				
			||||||
 | 
					  * osmux: Make sure RTP AMR feed to osmux is in octet-aligned mode
 | 
				
			||||||
 | 
					  * Improve logging on AMR OA<->BWE conversion failure
 | 
				
			||||||
 | 
					  * osmux: Rotate over available Osmux CID when allocating a new one
 | 
				
			||||||
 | 
					  * osmux: Use new osmux_xfrm_input API to set name on each link
 | 
				
			||||||
 | 
					  * iuup: Use osmo_amr_ft_valid() API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * libosmo-mgcp-client: add -no-undefined to *_la_LDFLAGS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * mgcp_e1: fix apidoc
 | 
				
			||||||
 | 
					  * mgcp_network: improve coment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Max ]
 | 
				
			||||||
 | 
					  * Set working directory in systemd service file
 | 
				
			||||||
 | 
					  * Add realtime scheduling and set priority in service file
 | 
				
			||||||
 | 
					  * ctrl: take both address and port from vty config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * Make osmo_mgcpc_ep_fsm_pre_term() static
 | 
				
			||||||
 | 
					  * Support building with -Werror=strict-prototypes / -Werror=old-style-definition
 | 
				
			||||||
 | 
					  * Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
 | 
				
			||||||
 | 
					  * update outdated vty copyright statement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * mgcp_client_pool.h: add missing stdbool include
 | 
				
			||||||
 | 
					  * Fix various typos
 | 
				
			||||||
 | 
					  * mgcp_client: add new clearmode codec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * AMR->IuUP: do not crash on AMR data before IuUP Init
 | 
				
			||||||
 | 
					  * AMR->IuUP: properly translate Q -> FQC
 | 
				
			||||||
 | 
					  * IuUP->AMR: do not patch payload type a second time
 | 
				
			||||||
 | 
					  * IuUP->AMR: log whether converting to AMR OA or BE
 | 
				
			||||||
 | 
					  * AMR->IuUP: log conversion, like for the flipside
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 07 Feb 2023 16:58:41 +0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-mgw (1.10.0) unstable; urgency=medium
 | 
					osmo-mgw (1.10.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,10 +6,10 @@ Build-Depends: debhelper (>=9),
 | 
				
			|||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.7.0),
 | 
					               libosmocore-dev (>= 1.8.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.2.0),
 | 
					               libosmo-netif-dev (>= 1.3.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.3.0),
 | 
					               libosmo-abis-dev (>= 1.4.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.3.0)
 | 
					               osmo-gsm-manuals-dev (>= 1.4.0)
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
				
			||||||
@@ -21,7 +21,7 @@ Multi-Arch: foreign
 | 
				
			|||||||
Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
					Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
				
			||||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libosmo-mgcp-client9
 | 
					Package: libosmo-mgcp-client11
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
@@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
 | 
				
			|||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Depends: libosmo-mgcp-client9 (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: libosmo-mgcp-client11 (= ${binary:Version}), ${misc:Depends}
 | 
				
			||||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
					Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw-doc
 | 
					Package: osmo-mgw-doc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_endp.h \
 | 
						mgcp_endp.h \
 | 
				
			||||||
	mgcp_sdp.h \
 | 
						mgcp_sdp.h \
 | 
				
			||||||
	mgcp_codec.h \
 | 
						mgcp_codec.h \
 | 
				
			||||||
	mgcp_ctrl.h \
 | 
					 | 
				
			||||||
	mgcp_trunk.h \
 | 
						mgcp_trunk.h \
 | 
				
			||||||
	debug.h \
 | 
						debug.h \
 | 
				
			||||||
	mgcp_ratectr.h \
 | 
						mgcp_ratectr.h \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@
 | 
				
			|||||||
enum {
 | 
					enum {
 | 
				
			||||||
	DRTP,
 | 
						DRTP,
 | 
				
			||||||
	DE1,
 | 
						DE1,
 | 
				
			||||||
 | 
						DOSMUX,
 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
@@ -156,24 +157,26 @@ struct mgcp_config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	enum mgcp_role role;
 | 
						enum mgcp_role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* osmux translator: 0 means disabled, 1 means enabled */
 | 
						struct {
 | 
				
			||||||
	int osmux;
 | 
							/* Osmux usage policy: */
 | 
				
			||||||
	/* addr to bind the server to */
 | 
							enum osmux_usage usage;
 | 
				
			||||||
	char osmux_addr[INET6_ADDRSTRLEN];
 | 
							/* addr to bind the server to */
 | 
				
			||||||
	/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
 | 
							char *local_addr_v4;
 | 
				
			||||||
	 * the osmux socket is already initialized.
 | 
							char *local_addr_v6;
 | 
				
			||||||
	 */
 | 
							/* osmux port */
 | 
				
			||||||
	int osmux_init;
 | 
							uint16_t local_port;
 | 
				
			||||||
	/* osmux batch factor: from 1 to 4 maximum */
 | 
							/* The osmux socket is allocated on demand (1st time used).
 | 
				
			||||||
	int osmux_batch;
 | 
							* This tells us if the osmux socket is already initialized.  */
 | 
				
			||||||
	/* osmux batch size (in bytes) */
 | 
							bool initialized;
 | 
				
			||||||
	int osmux_batch_size;
 | 
							/* osmux batch factor: from 1 to 4 maximum */
 | 
				
			||||||
	/* osmux port */
 | 
							int batch_factor;
 | 
				
			||||||
	uint16_t osmux_port;
 | 
							/* osmux batch size (in bytes) */
 | 
				
			||||||
	/* Pad circuit with dummy messages until we see the first voice
 | 
							int batch_size;
 | 
				
			||||||
	 * message.
 | 
							/* Pad circuit with dummy AMR frames if no payload to transmit is available */
 | 
				
			||||||
	 */
 | 
							bool dummy_padding;
 | 
				
			||||||
	uint16_t osmux_dummy;
 | 
							/* Whether peer is behind NAT (Retrieve remote addr from 1st received Osmux packet) */
 | 
				
			||||||
 | 
							bool peer_behind_nat;
 | 
				
			||||||
 | 
						} osmux;
 | 
				
			||||||
	/* domain name of the media gateway */
 | 
						/* domain name of the media gateway */
 | 
				
			||||||
	char domain[255+1];
 | 
						char domain[255+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,4 +210,4 @@ int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
					int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
				
			||||||
		     uint8_t prio);
 | 
							     uint8_t prio);
 | 
				
			||||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
 | 
					int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,4 +17,5 @@ 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 struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
					bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,8 +46,7 @@ LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
				
			|||||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
					/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
				
			||||||
enum mgcp_conn_rtp_type {
 | 
					enum mgcp_conn_rtp_type {
 | 
				
			||||||
	MGCP_RTP_DEFAULT	= 0,
 | 
						MGCP_RTP_DEFAULT	= 0,
 | 
				
			||||||
	MGCP_OSMUX_BSC,
 | 
						MGCP_RTP_OSMUX,
 | 
				
			||||||
	MGCP_OSMUX_BSC_NAT,
 | 
					 | 
				
			||||||
	MGCP_RTP_IUUP,
 | 
						MGCP_RTP_IUUP,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,19 +79,20 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* Osmux state: disabled, activating, active */
 | 
							/* Osmux state: disabled, activating, active */
 | 
				
			||||||
		enum osmux_state state;
 | 
							enum osmux_state state;
 | 
				
			||||||
		/* Is cid holding valid data? is it allocated from pool? */
 | 
							/* Is local_cid holding valid data? is it allocated from pool? */
 | 
				
			||||||
		bool cid_allocated;
 | 
							bool local_cid_allocated;
 | 
				
			||||||
		/* Allocated Osmux circuit ID for this conn */
 | 
							/* Allocated local Osmux circuit ID for this conn */
 | 
				
			||||||
		uint8_t cid;
 | 
							uint8_t local_cid;
 | 
				
			||||||
		/* handle to batch messages */
 | 
							/* Is remote_cid holding valid data? was it already received from client? */
 | 
				
			||||||
 | 
							bool remote_cid_present;
 | 
				
			||||||
 | 
							/* Received remote Osmux circuit ID for this conn */
 | 
				
			||||||
 | 
							uint8_t remote_cid;
 | 
				
			||||||
 | 
							/* handle to batch messages, shared (refcounted) among several conns */
 | 
				
			||||||
		struct osmux_in_handle *in;
 | 
							struct osmux_in_handle *in;
 | 
				
			||||||
		/* handle to unbatch messages */
 | 
							/* handle to unbatch messages, one allocated and owned per conn */
 | 
				
			||||||
		struct osmux_out_handle out;
 | 
							struct osmux_out_handle *out;
 | 
				
			||||||
		/* statistics */
 | 
							/* statistics: */
 | 
				
			||||||
		struct {
 | 
							struct rate_ctr_group *ctrg;
 | 
				
			||||||
			uint32_t chunks;
 | 
					 | 
				
			||||||
			uint32_t octets;
 | 
					 | 
				
			||||||
		} stats;
 | 
					 | 
				
			||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
@@ -103,7 +103,7 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
		struct osmo_iuup_rnl_prim *init_ind;
 | 
							struct osmo_iuup_rnl_prim *init_ind;
 | 
				
			||||||
	} iuup;
 | 
						} iuup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr_group *rate_ctr_group;
 | 
						struct rate_ctr_group *ctrg;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! MGCP connection (untyped) */
 | 
					/*! MGCP connection (untyped) */
 | 
				
			||||||
@@ -145,12 +145,12 @@ struct mgcp_conn {
 | 
				
			|||||||
enum {
 | 
					enum {
 | 
				
			||||||
	IN_STREAM_ERR_TSTMP_CTR,
 | 
						IN_STREAM_ERR_TSTMP_CTR,
 | 
				
			||||||
	OUT_STREAM_ERR_TSTMP_CTR,
 | 
						OUT_STREAM_ERR_TSTMP_CTR,
 | 
				
			||||||
        RTP_PACKETS_RX_CTR,
 | 
						RTP_PACKETS_RX_CTR,
 | 
				
			||||||
        RTP_OCTETS_RX_CTR,
 | 
						RTP_OCTETS_RX_CTR,
 | 
				
			||||||
        RTP_PACKETS_TX_CTR,
 | 
						RTP_PACKETS_TX_CTR,
 | 
				
			||||||
        RTP_OCTETS_TX_CTR,
 | 
						RTP_OCTETS_TX_CTR,
 | 
				
			||||||
        RTP_DROPPED_PACKETS_CTR,
 | 
						RTP_DROPPED_PACKETS_CTR,
 | 
				
			||||||
        RTP_NUM_CONNECTIONS,
 | 
						RTP_NUM_CONNECTIONS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
					/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
				
			||||||
@@ -163,7 +163,7 @@ static const struct rate_ctr_desc mgcp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
						[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
				
			||||||
	[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
						[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
				
			||||||
	[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
						[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
				
			||||||
	[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "dropped rtp packets."}
 | 
						[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "Dropped rtp packets."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
					/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
				
			||||||
@@ -181,9 +181,49 @@ 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."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Osmux connection related counters */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						OSMUX_CHUNKS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_OCTETS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_RTP_PACKETS_TX_CTR,
 | 
				
			||||||
 | 
						OSMUX_RTP_PACKETS_TX_DROPPED_CTR,
 | 
				
			||||||
 | 
						OSMUX_AMR_OCTETS_TX_CTR,
 | 
				
			||||||
 | 
						/* Only available in global stats: */
 | 
				
			||||||
 | 
						OSMUX_NUM_CONNECTIONS,
 | 
				
			||||||
 | 
						OSMUX_PACKETS_RX_CTR,
 | 
				
			||||||
 | 
						OSMUX_PACKETS_TX_CTR,
 | 
				
			||||||
 | 
						OSMUX_DROPPED_PACKETS_CTR,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
				
			||||||
 | 
					 * exist for the lifetime of an RTP connection.
 | 
				
			||||||
 | 
					 * Must be kept in sync with all_rtp_conn_rate_ctr_desc below */
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc mgcp_conn_osmux_rate_ctr_desc[] = {
 | 
				
			||||||
 | 
						[OSMUX_CHUNKS_RX_CTR] = {"osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
				
			||||||
 | 
						[OSMUX_OCTETS_RX_CTR] = {"osmux:octets_rx", "Inbound Osmux octets."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_CTR] = {"osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_AMR_OCTETS_TX_CTR] = {"osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Aggregated Osmux connection stats. These are updated when an Osmux connection is freed.
 | 
				
			||||||
 | 
					 * Must be kept in sync with mgcp_conn_osmux_rate_ctr_desc above */
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc all_osmux_conn_rate_ctr_desc[] = {
 | 
				
			||||||
 | 
						[OSMUX_CHUNKS_RX_CTR] = {"all_osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
				
			||||||
 | 
						[OSMUX_OCTETS_RX_CTR] = {"all_osmux:octets_rx", "Inbound Osmux octets."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_CTR] = {"all_osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"all_osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
				
			||||||
 | 
						[OSMUX_AMR_OCTETS_TX_CTR] = {"all_osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
				
			||||||
 | 
						/* These last counters below do not exist in per-connection stats, only here: */
 | 
				
			||||||
 | 
						[OSMUX_NUM_CONNECTIONS] = {"all_osmux:num_closed_conns", "Total number of osmux connections closed."},
 | 
				
			||||||
 | 
						[OSMUX_PACKETS_RX_CTR] = {"all_osmux:packets_rx", "Total inbound UDP/Osmux packets."},
 | 
				
			||||||
 | 
						[OSMUX_PACKETS_TX_CTR] = {"all_osmux:packets_tx", "Total outbound UDP/Osmux packets."},
 | 
				
			||||||
 | 
						[OSMUX_DROPPED_PACKETS_CTR] = {"all_osmux:dropped_packets", "Dropped outbound UDP/Osmux packets."}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
					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;
 | 
						return conn->type == MGCP_RTP_OSMUX;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,24 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
					 | 
				
			||||||
 * 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
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
					 | 
				
			||||||
                                             const char *bind_addr, uint16_t port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -40,8 +40,13 @@ LOGP(cat, level, "endpoint:%s " fmt, \
 | 
				
			|||||||
     endp ? endp->name : "none", \
 | 
					     endp ? endp->name : "none", \
 | 
				
			||||||
     ## args)
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum rtp_proto {
 | 
				
			||||||
 | 
						MGCP_PROTO_RTP,
 | 
				
			||||||
 | 
						MGCP_PROTO_RTCP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct osmo_rtp_msg_ctx {
 | 
					struct osmo_rtp_msg_ctx {
 | 
				
			||||||
	int proto;
 | 
						enum rtp_proto proto;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_src;
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
	struct osmo_sockaddr *from_addr;
 | 
						struct osmo_sockaddr *from_addr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* The following constant defines an RTP dummy payload that is used for
 | 
					/* The following constant defines an RTP dummy payload that is used for
 | 
				
			||||||
 * "UDP Hole Punching" (NAT) */
 | 
					 * "UDP Hole Punching" (NAT) */
 | 
				
			||||||
static const char rtp_dummy_payload[] = { 0x23 };
 | 
					#define MGCP_DUMMY_LOAD 0x23
 | 
				
			||||||
 | 
					static const char rtp_dummy_payload[] = { MGCP_DUMMY_LOAD };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the data in a given message buffer matches the rtp dummy payload
 | 
					/* Check if the data in a given message buffer matches the rtp dummy payload
 | 
				
			||||||
 * defined above */
 | 
					 * defined above */
 | 
				
			||||||
@@ -92,7 +93,7 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	struct osmo_sockaddr addr;
 | 
						struct osmo_sockaddr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* in network byte order */
 | 
						/* in network byte order */
 | 
				
			||||||
	int rtp_port, rtcp_port;
 | 
						int rtcp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* currently selected audio codec */
 | 
						/* currently selected audio codec */
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
@@ -156,7 +157,7 @@ void mgcp_patch_and_count(const 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 osmo_sockaddr *addr, struct msgb *msg);
 | 
								  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
				
			||||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* payload processing default functions */
 | 
					/* payload processing default functions */
 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
				
			||||||
@@ -178,5 +179,9 @@ void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_stat
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
				 int id, int inc);
 | 
									 int id, int inc);
 | 
				
			||||||
 | 
					void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									 int id);
 | 
				
			||||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
					void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
				
			||||||
uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
					uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,8 @@ struct mgcp_ratectr_trunk {
 | 
				
			|||||||
	struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
						struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
				
			||||||
	/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
						/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
				
			||||||
	struct rate_ctr_group *all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_rtp_conn_stats;
 | 
				
			||||||
 | 
						/* Rate counter group which aggregates stats of individual Osmux connections. */
 | 
				
			||||||
 | 
						struct rate_ctr_group *all_osmux_conn_stats;
 | 
				
			||||||
	/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
						/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
				
			||||||
	struct rate_ctr_group *e1_stats;
 | 
						struct rate_ctr_group *e1_stats;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,22 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					struct mgcp_trunk;
 | 
				
			||||||
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define OSMUX_PORT	1984
 | 
					int osmux_init(struct mgcp_trunk *trunk);
 | 
				
			||||||
 | 
					int osmux_init_conn(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
enum {
 | 
					int conn_osmux_enable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
	OSMUX_ROLE_BSC = 0,
 | 
					 | 
				
			||||||
	OSMUX_ROLE_BSC_NAT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int osmux_init(int role, struct mgcp_config *cfg);
 | 
					 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					 | 
				
			||||||
		      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_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
					int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg);
 | 
				
			||||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
 | 
					int osmux_send_dummy(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
					void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
				
			||||||
int osmux_cid_pool_get_next(void);
 | 
					int osmux_cid_pool_get_next(void);
 | 
				
			||||||
@@ -29,10 +26,14 @@ int osmux_cid_pool_count_used(void);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum osmux_state {
 | 
					enum osmux_state {
 | 
				
			||||||
	OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
						OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
				
			||||||
	OSMUX_STATE_ACTIVATING,   /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref osmux_enable_endpoint. */
 | 
						OSMUX_STATE_ACTIVATING,   /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref conn_osmux_enable. */
 | 
				
			||||||
	OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
 | 
						OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref conn_osmux_enable and can process frames */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string osmux_state_strs[];
 | 
				
			||||||
 | 
					static inline const char *osmux_state_str(enum osmux_state val)
 | 
				
			||||||
 | 
					{ return get_value_string(osmux_state_strs, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum osmux_usage {
 | 
					enum osmux_usage {
 | 
				
			||||||
	OSMUX_USAGE_OFF = 0,
 | 
						OSMUX_USAGE_OFF = 0,
 | 
				
			||||||
	OSMUX_USAGE_ON = 1,
 | 
						OSMUX_USAGE_ON = 1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* 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 NULL /* INADDR(6)_ANY */
 | 
					#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
 | 
					#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
 | 
				
			||||||
#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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,6 +50,7 @@ enum mgcp_codecs {
 | 
				
			|||||||
	CODEC_AMR_8000_1 = 112,
 | 
						CODEC_AMR_8000_1 = 112,
 | 
				
			||||||
	CODEC_AMRWB_16000_1 = 113,
 | 
						CODEC_AMRWB_16000_1 = 113,
 | 
				
			||||||
	CODEC_IUFP = 96,
 | 
						CODEC_IUFP = 96,
 | 
				
			||||||
 | 
						CODEC_CLEARMODE = 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
/* Note: when new codec types are added, the corresponding value strings
 | 
					/* Note: when new codec types are added, the corresponding value strings
 | 
				
			||||||
 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
					 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
				
			||||||
@@ -140,7 +141,7 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
				
			|||||||
struct mgcp_client *mgcp_client_init(void *ctx,
 | 
					struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			||||||
				     struct mgcp_client_conf *conf);
 | 
									     struct mgcp_client_conf *conf);
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
				
			||||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
 | 
					int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports) OSMO_DEPRECATED("Use mgcp_client_connect() instead");
 | 
				
			||||||
void mgcp_client_disconnect(struct mgcp_client *mgcp);
 | 
					void mgcp_client_disconnect(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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ struct mgcp_client {
 | 
				
			|||||||
	mgcp_trans_id_t next_trans_id;
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
	struct llist_head inuse_endpoints;
 | 
						struct llist_head inuse_endpoints;
 | 
				
			||||||
	struct mgcp_client_pool *pool;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_inuse_endpoint {
 | 
					struct mgcp_inuse_endpoint {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,21 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client;
 | 
					struct mgcp_client;
 | 
				
			||||||
struct mgcp_client_pool;
 | 
					struct mgcp_client_pool;
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
 | 
					struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
 | 
				
			||||||
 | 
					int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
 | 
				
			||||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
					unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr);
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 | 
					bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,31 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Struct to handle a pool of MGWs. (Use _pool functions) */
 | 
				
			||||||
 | 
					struct mgcp_client_pool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
 | 
				
			||||||
 | 
						 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp_client_single;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A list that manages the pool members (see mgcp_client_pool_member->list above) */
 | 
				
			||||||
 | 
						struct llist_head member_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
 | 
				
			||||||
 | 
						 * mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						char *vty_indent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						struct cmd_node *vty_node;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Struct to handle a member of a pool of MGWs. */
 | 
					/* Struct to handle a member of a pool of MGWs. */
 | 
				
			||||||
struct mgcp_client_pool_member {
 | 
					struct mgcp_client_pool_member {
 | 
				
			||||||
 | 
						/* Entry in llist mgcp_client_pool->pool. */
 | 
				
			||||||
	struct llist_head list;
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The pool managing this object: */
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
 | 
						/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
 | 
				
			||||||
	 * the log. */
 | 
						 * the log. */
 | 
				
			||||||
	unsigned int nr;
 | 
						unsigned int nr;
 | 
				
			||||||
@@ -24,22 +46,7 @@ struct mgcp_client_pool_member {
 | 
				
			|||||||
	unsigned int refcount;
 | 
						unsigned int refcount;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Struct to handle a pool of MGWs. (Use _pool functions) */
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr);
 | 
				
			||||||
struct mgcp_client_pool {
 | 
					void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 | 
					int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
	/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
 | 
					 | 
				
			||||||
	 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp_client_single;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* A list that manages the pool members (see above) */
 | 
					 | 
				
			||||||
	struct llist_head pool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
 | 
					 | 
				
			||||||
	 * mgcp_client_pool_vty_init() */
 | 
					 | 
				
			||||||
	char *vty_indent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
 | 
					 | 
				
			||||||
	struct cmd_node *vty_node;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ AM_LDFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# This is not at all related to the release version, but a range of supported
 | 
					# This is not at all related to the release version, but a range of supported
 | 
				
			||||||
# API versions. Read TODO_RELEASE in the source tree's root!
 | 
					# API versions. Read TODO_RELEASE in the source tree's root!
 | 
				
			||||||
MGCP_CLIENT_LIBVERSION=10:0:1
 | 
					MGCP_CLIENT_LIBVERSION=11:0:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -35,4 +35,8 @@ libosmo_mgcp_client_la_SOURCES = \
 | 
				
			|||||||
	mgcp_client_pool.c \
 | 
						mgcp_client_pool.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
 | 
					libosmo_mgcp_client_la_LDFLAGS = \
 | 
				
			||||||
 | 
						$(AM_LDFLAGS) \
 | 
				
			||||||
 | 
						-version-info $(MGCP_CLIENT_LIBVERSION) \
 | 
				
			||||||
 | 
						-no-undefined \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,7 @@ const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			|||||||
	{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
						{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
				
			||||||
	{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
						{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
				
			||||||
	{ CODEC_IUFP, "VND.3GPP.IUFP/16000" },
 | 
						{ CODEC_IUFP, "VND.3GPP.IUFP/16000" },
 | 
				
			||||||
 | 
						{ CODEC_CLEARMODE, "CLEARMODE/8000" },
 | 
				
			||||||
	{ 0, NULL },
 | 
						{ 0, NULL },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -442,7 +443,7 @@ static int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "MGW offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return osmux_cid;
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -726,10 +727,6 @@ static int mgcp_do_read(struct osmo_fd *fd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	} else if (ret > 4096 - 128) {
 | 
					 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg->l2h = msgb_put(msg, ret);
 | 
						msg->l2h = msgb_put(msg, ret);
 | 
				
			||||||
@@ -773,7 +770,7 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
 | 
						mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
 | 
				
			||||||
		MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
 | 
							MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
 | 
				
			||||||
	mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
 | 
						mgcp->actual.local_port = conf->local_port > 0 ? (uint16_t)conf->local_port :
 | 
				
			||||||
		MGCP_CLIENT_LOCAL_PORT_DEFAULT;
 | 
							MGCP_CLIENT_LOCAL_PORT_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
 | 
						mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
 | 
				
			||||||
@@ -803,49 +800,6 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	return mgcp;
 | 
						return mgcp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wq = &mgcp->wq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < retry_n_ports + 1; i++) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Initialize socket with the currently configured port number */
 | 
					 | 
				
			||||||
		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,
 | 
					 | 
				
			||||||
					 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
					 | 
				
			||||||
		if (rc > 0)
 | 
					 | 
				
			||||||
			return rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* If there is a different port than the default port configured then we assume that the user has
 | 
					 | 
				
			||||||
		 * chosen that port conciously and we will not try to resolve this by silently choosing a different
 | 
					 | 
				
			||||||
		 * port. */
 | 
					 | 
				
			||||||
		if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (i == retry_n_ports) {
 | 
					 | 
				
			||||||
			/* Last try failed */
 | 
					 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_NOTICE, "Failed to bind to %s:%d -- check configuration!\n",
 | 
					 | 
				
			||||||
			     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port);
 | 
					 | 
				
			||||||
			if (retry_n_ports == 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			/* Choose a new port number to try next */
 | 
					 | 
				
			||||||
			LOGPMGW(mgcp, LOGL_NOTICE,
 | 
					 | 
				
			||||||
			     "Failed to bind to %s:%d, retrying with port %d -- check configuration!\n",
 | 
					 | 
				
			||||||
			     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
					 | 
				
			||||||
			     mgcp->actual.local_port + 1);
 | 
					 | 
				
			||||||
			mgcp->actual.local_port++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPMGW(mgcp, LOGL_FATAL, "Failed to find a port to bind on %u times -- check configuration!\n", i);
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
					/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
				
			||||||
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
					static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -882,9 +836,8 @@ static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! Initialize client connection (opens socket)
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \param[in] retry_n_ports number of consecutive local ports that should be used to retry on failure.
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -903,7 +856,9 @@ int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
						osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = init_socket(mgcp, retry_n_ports);
 | 
						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,
 | 
				
			||||||
 | 
									 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_FATAL,
 | 
							LOGPMGW(mgcp, LOGL_FATAL,
 | 
				
			||||||
		     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
							     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
				
			||||||
@@ -929,12 +884,12 @@ error_close_fd:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initialize client connection (opens socket)
 | 
					/*! DEPRECATED: Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \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_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return mgcp_client_connect2(mgcp, 99);
 | 
						return mgcp_client_connect(mgcp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Terminate client connection
 | 
					/*! Terminate client connection
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -227,7 +227,7 @@ static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
					static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fill_event_names()
 | 
					static void fill_event_names(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
						for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
				
			||||||
@@ -243,7 +243,7 @@ static void fill_event_names()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
					static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
				
			||||||
	fill_event_names();
 | 
						fill_event_names();
 | 
				
			||||||
@@ -997,7 +997,7 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
 | 
					static void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -760,7 +760,7 @@ const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			|||||||
	return buf;
 | 
						return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
 | 
					static __attribute__((constructor)) void osmo_mgcp_client_fsm_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm-generic/errno.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>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
@@ -27,32 +28,6 @@
 | 
				
			|||||||
#define LOGPPMGW(pool_member, level, fmt, args...) \
 | 
					#define LOGPPMGW(pool_member, level, fmt, args...) \
 | 
				
			||||||
LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
 | 
					LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Get a human readable name for a given pool member. */
 | 
					 | 
				
			||||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const struct mgcp_client *mpcp_client;
 | 
					 | 
				
			||||||
	struct mgcp_client mpcp_client_dummy;
 | 
					 | 
				
			||||||
	static char name[512];
 | 
					 | 
				
			||||||
	const char *description;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pool_member)
 | 
					 | 
				
			||||||
		return "(null)";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
 | 
					 | 
				
			||||||
	 * initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
 | 
					 | 
				
			||||||
	if (!pool_member->client) {
 | 
					 | 
				
			||||||
		memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
 | 
					 | 
				
			||||||
		mpcp_client = &mpcp_client_dummy;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		mpcp_client = pool_member->client;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	description = mgcp_client_name(mpcp_client);
 | 
					 | 
				
			||||||
	snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return name;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
 | 
					/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
 | 
				
			||||||
 *  mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
 | 
					 *  mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
 | 
				
			||||||
 *  \param[in] talloc_ctx talloc context. */
 | 
					 *  \param[in] talloc_ctx talloc context. */
 | 
				
			||||||
@@ -64,7 +39,7 @@ struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
 | 
				
			|||||||
	if (!pool)
 | 
						if (!pool)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&pool->pool);
 | 
						INIT_LLIST_HEAD(&pool->member_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pool;
 | 
						return pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -77,29 +52,11 @@ unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
 | 
				
			|||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	unsigned int pool_members_initialized = 0;
 | 
						unsigned int pool_members_initialized = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Initialize client */
 | 
							/* Initialize client */
 | 
				
			||||||
		pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
							if (mgcp_client_pool_member_reinit_client(pool_member) == 0)
 | 
				
			||||||
		if (!pool_member->client) {
 | 
								pool_members_initialized++;
 | 
				
			||||||
			LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Set backpointer so that we can detect later that this MGCP client is managed
 | 
					 | 
				
			||||||
		 * by this pool. */
 | 
					 | 
				
			||||||
		pool_member->client->pool = pool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Connect client */
 | 
					 | 
				
			||||||
		if (mgcp_client_connect2(pool_member->client, 0)) {
 | 
					 | 
				
			||||||
			LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
 | 
					 | 
				
			||||||
				 pool_member->conf.remote_addr, pool_member->conf.remote_port);
 | 
					 | 
				
			||||||
			talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
			pool_member->client = NULL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pool_members_initialized++;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pool_members_initialized;
 | 
						return pool_members_initialized;
 | 
				
			||||||
@@ -118,23 +75,37 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
 | 
				
			|||||||
	pool->mgcp_client_single = mgcp_client;
 | 
						pool->mgcp_client_single = mgcp_client;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Lookup the selected MGCP client config by its reference number */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							if (pool_member->nr == nr)
 | 
				
			||||||
 | 
								return pool_member;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
					/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
				
			||||||
 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
					 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
				
			||||||
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
					static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member_picked = NULL;
 | 
						struct mgcp_client_pool_member *pool_member_picked = NULL;
 | 
				
			||||||
	unsigned int n_pool_members = llist_count(&pool->pool);
 | 
						unsigned int n_pool_members = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							n_pool_members++;
 | 
				
			||||||
		if (pool_member->blocked == false && pool_member->client) {
 | 
							if (pool_member->blocked == false && pool_member->client) {
 | 
				
			||||||
			if (!pool_member_picked)
 | 
								if (!pool_member_picked)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
			else if (pool_member_picked->refcount > pool_member->refcount)
 | 
								else if (pool_member_picked->refcount > pool_member->refcount)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
 | 
								LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u)\n",
 | 
				
			||||||
				 pool_member->nr);
 | 
									 __func__, pool_member->nr, pool_member->blocked, !!pool_member->client);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,26 +134,24 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
 | 
				
			|||||||
	 *  by the application code. */
 | 
						 *  by the application code. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* When the pool is empty, return a single MGCP client if it is registered. */
 | 
						/* When the pool is empty, return a single MGCP client if it is registered. */
 | 
				
			||||||
	if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
 | 
						if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
 | 
				
			||||||
		     mgcp_client_name(pool->mgcp_client_single));
 | 
							     mgcp_client_name(pool->mgcp_client_single));
 | 
				
			||||||
		return pool->mgcp_client_single;
 | 
							return pool->mgcp_client_single;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Abort when the pool is empty */
 | 
						/* Abort when the pool is empty */
 | 
				
			||||||
	if (llist_empty(&pool->pool)) {
 | 
						if (llist_empty(&pool->member_list)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Pick a suitable pool member */
 | 
						/* Pick a suitable pool member */
 | 
				
			||||||
	pool_member = mgcp_client_pool_pick(pool);
 | 
						pool_member = mgcp_client_pool_pick(pool);
 | 
				
			||||||
	if (pool_member) {
 | 
						if (!pool_member)
 | 
				
			||||||
		pool_member->refcount++;
 | 
							return NULL;
 | 
				
			||||||
		return pool_member->client;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return mgcp_client_pool_member_get(pool_member);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! put an MGCP client back into the pool (decrement reference counter).
 | 
					/*! put an MGCP client back into the pool (decrement reference counter).
 | 
				
			||||||
@@ -194,23 +163,130 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
 | 
				
			|||||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	struct mgcp_client_pool *pool;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mgcp_client)
 | 
						if (!mgcp_client)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_client->pool)
 | 
						if (!mgcp_client->pool_member)
 | 
				
			||||||
		pool = mgcp_client->pool;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						pool_member = mgcp_client->pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
						if (pool_member->refcount == 0) {
 | 
				
			||||||
		if (pool_member->client == mgcp_client) {
 | 
							LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
				
			||||||
			if (pool_member->refcount == 0) {
 | 
							return;
 | 
				
			||||||
				LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			pool_member->refcount--;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						pool_member->refcount--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***************************
 | 
				
			||||||
 | 
					 * mgcp_client_pool_member:
 | 
				
			||||||
 | 
					 ***************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Allocate an mgcp_client_pool_member.
 | 
				
			||||||
 | 
					 *  \param[in] pool MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] nr Reference number of the pool member.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pool_member = talloc_zero(pool, struct mgcp_client_pool_member);
 | 
				
			||||||
 | 
						OSMO_ASSERT(pool_member);
 | 
				
			||||||
 | 
						mgcp_client_conf_init(&pool_member->conf);
 | 
				
			||||||
 | 
						pool_member->pool = pool;
 | 
				
			||||||
 | 
						pool_member->nr = nr;
 | 
				
			||||||
 | 
						llist_add_tail(&pool_member->list, &pool->member_list);
 | 
				
			||||||
 | 
						return pool_member;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Free an mgcp_client_pool_member allocated through mgcp_client_pool_member_alloc().
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * It also frees the associated MGCP client if present.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_del(&pool_member->list);
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						talloc_free(pool_member);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Recreate and reconnect the MGCP client associated to the pool descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Get rid of a possibly existing old MGCP client instance first */
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Initialize client */
 | 
				
			||||||
 | 
						pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
				
			||||||
 | 
						pool_member->client->pool_member = pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Connect client */
 | 
				
			||||||
 | 
						if (mgcp_client_connect(pool_member->client)) {
 | 
				
			||||||
 | 
							LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
 | 
				
			||||||
 | 
									pool_member->conf.remote_addr, pool_member->conf.remote_port);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
							pool_member->client = NULL;
 | 
				
			||||||
 | 
							return -ECONNABORTED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get a human readable name for a given pool member. */
 | 
				
			||||||
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_client *mpcp_client;
 | 
				
			||||||
 | 
						struct mgcp_client mpcp_client_dummy;
 | 
				
			||||||
 | 
						static char name[512];
 | 
				
			||||||
 | 
						const char *description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pool_member)
 | 
				
			||||||
 | 
							return "(null)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
 | 
				
			||||||
 | 
						 * initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
 | 
				
			||||||
 | 
							mpcp_client = &mpcp_client_dummy;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mpcp_client = pool_member->client;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						description = mgcp_client_name(mpcp_client);
 | 
				
			||||||
 | 
						snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get the MGCP client associated with the pool reference from the pool (increment reference counter).
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns MGCP client descriptor, NULL if no member was not ready.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pool_member->refcount++;
 | 
				
			||||||
 | 
						return pool_member->client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Get whether the MGCP client associated with the pool reference is blocked by policy.
 | 
				
			||||||
 | 
					 *  \param[in] pool_member MGCP client pool descriptor.
 | 
				
			||||||
 | 
					 *  \returns true if blocked, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return pool_member->blocked;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,10 +32,11 @@
 | 
				
			|||||||
#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>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
					#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Only common (non-pooled) VTY connands will use this talloc context. All
 | 
					/* Only common (non-pooled) VTY commands will use this talloc context. All
 | 
				
			||||||
 * pooled VTY commands will use the pool (global_mgcp_client_pool) as
 | 
					 * pooled VTY commands will use the pool (global_mgcp_client_pool) as
 | 
				
			||||||
 * talloc context. */
 | 
					 * talloc context. */
 | 
				
			||||||
static void *global_mgcp_client_ctx = NULL;
 | 
					static void *global_mgcp_client_ctx = NULL;
 | 
				
			||||||
@@ -51,13 +52,18 @@ struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
						if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
				
			||||||
		return vty->index;
 | 
							return vty->index;
 | 
				
			||||||
	else
 | 
					
 | 
				
			||||||
		return global_mgcp_client_conf;
 | 
						/* Global single MGCP config, deprecated: */
 | 
				
			||||||
 | 
						vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
				
			||||||
 | 
							"You should consider reading User Manual and migrating to 'mgw' node.%s",
 | 
				
			||||||
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return global_mgcp_client_conf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "mgw local-ip " VTY_IPV46_CMD,
 | 
					      "local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "local bind to connect to MGW from\n"
 | 
					      "local bind to connect to MGW from\n"
 | 
				
			||||||
      "local bind IPv4 address\n"
 | 
					      "local bind IPv4 address\n"
 | 
				
			||||||
      "local bind IPv6 address\n")
 | 
					      "local bind IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -72,10 +78,16 @@ ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
 | 
				
			|||||||
		 "mgcpgw local-ip A.B.C.D",
 | 
							 "mgcpgw local-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind IP address\n")
 | 
							 "local bind IP address\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_local_ip,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_local_ip_cmd,
 | 
				
			||||||
 | 
							 "mgw local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
 | 
							 MGW_STR "local bind to connect to MGW from\n"
 | 
				
			||||||
 | 
							 "local bind IPv4 address\n"
 | 
				
			||||||
 | 
							 "local bind IPv6 address\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
					DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
				
			||||||
      "mgw local-port <0-65535>",
 | 
					      "local-port <0-65535>",
 | 
				
			||||||
      MGW_STR "local port to connect to MGW from\n"
 | 
					      "local port to connect to MGW from\n"
 | 
				
			||||||
      "local bind port\n")
 | 
					      "local bind port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -87,10 +99,15 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
 | 
				
			|||||||
		 "mgcpgw local-port <0-65535>",
 | 
							 "mgcpgw local-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind port\n")
 | 
							 "local bind port\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_local_port,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_local_port_cmd,
 | 
				
			||||||
 | 
							 "mgw local-port <0-65535>",
 | 
				
			||||||
 | 
							 MGW_STR "local port to connect to MGW from\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 " VTY_IPV46_CMD,
 | 
					      "remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      MGW_STR "remote IP address to reach the MGW at\n"
 | 
					      "remote IP address to reach the MGW at\n"
 | 
				
			||||||
      "remote IPv4 address\n"
 | 
					      "remote IPv4 address\n"
 | 
				
			||||||
      "remote IPv6 address\n")
 | 
					      "remote IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -104,10 +121,16 @@ ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
 | 
				
			|||||||
		 "mgcpgw remote-ip A.B.C.D",
 | 
							 "mgcpgw remote-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind IP address\n")
 | 
							 "remote bind IP address\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_ip,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_remote_ip_cmd,
 | 
				
			||||||
 | 
							 "mgw remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
 | 
							 MGW_STR "remote IP address to reach the MGW at\n"
 | 
				
			||||||
 | 
							 "remote IPv4 address\n"
 | 
				
			||||||
 | 
							 "remote IPv6 address\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
					DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
				
			||||||
      "mgw remote-port <0-65535>",
 | 
					      "remote-port <0-65535>",
 | 
				
			||||||
      MGW_STR "remote port to reach the MGW at\n"
 | 
					      "remote port to reach the MGW at\n"
 | 
				
			||||||
      "remote port\n")
 | 
					      "remote port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -119,8 +142,13 @@ ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
 | 
				
			|||||||
		 "mgcpgw remote-port <0-65535>",
 | 
							 "mgcpgw remote-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind port\n")
 | 
							 "remote bind port\n")
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_remote_port,
 | 
				
			||||||
 | 
							 cfg_mgw_mgw_remote_port_cmd,
 | 
				
			||||||
 | 
							 "mgw remote-port <0-65535>",
 | 
				
			||||||
 | 
							 MGW_STR "remote port to reach the MGW at\n"
 | 
				
			||||||
 | 
							 "remote port\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
 | 
					DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
					      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
				
			||||||
      "-\n" "-\n")
 | 
					      "-\n" "-\n")
 | 
				
			||||||
@@ -130,7 +158,7 @@ DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
 | 
				
			|||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "usable range of endpoint identifiers\n"
 | 
					      MGW_STR "usable range of endpoint identifiers\n"
 | 
				
			||||||
      "set first useable endpoint identifier\n"
 | 
					      "set first useable endpoint identifier\n"
 | 
				
			||||||
@@ -158,8 +186,8 @@ ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_endpoint_domain_name,
 | 
					DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			||||||
      cfg_mgw_endpoint_domain_name_cmd,
 | 
					      cfg_mgw_endpoint_domain_name_cmd,
 | 
				
			||||||
      "mgw endpoint-domain NAME",
 | 
					      "endpoint-domain NAME",
 | 
				
			||||||
      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
					      "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
				
			||||||
      "Domain name, should be alphanumeric.\n")
 | 
					      "Domain name, should be alphanumeric.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -172,11 +200,16 @@ DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_endpoint_domain_name,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_endpoint_domain_name_cmd,
 | 
				
			||||||
 | 
					      "mgw endpoint-domain NAME",
 | 
				
			||||||
 | 
					      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
				
			||||||
 | 
					      "Domain name, should be alphanumeric.\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_reset_ep_name,
 | 
					DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			||||||
      cfg_mgw_reset_ep_name_cmd,
 | 
					      cfg_mgw_reset_ep_name_cmd,
 | 
				
			||||||
      "mgw reset-endpoint NAME",
 | 
					      "reset-endpoint NAME",
 | 
				
			||||||
      MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
					      "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
				
			||||||
      "e.g. 'rtpbridge/*'\n"
 | 
					      "e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -214,11 +247,17 @@ DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "mgw reset-endpoint NAME",
 | 
				
			||||||
 | 
					      MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
				
			||||||
 | 
					      "e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_no_reset_ep_name,
 | 
					DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
      cfg_mgw_no_reset_ep_name_cmd,
 | 
					      cfg_mgw_no_reset_ep_name_cmd,
 | 
				
			||||||
      "no mgw reset-endpoint NAME",
 | 
					      "no reset-endpoint NAME",
 | 
				
			||||||
      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
					      NO_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct reset_ep *reset_ep;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
@@ -235,6 +274,11 @@ DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			|||||||
	vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
						vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
	return CMD_WARNING;
 | 
						return CMD_WARNING;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
 | 
					      cfg_mgw_mgw_no_reset_ep_name_cmd,
 | 
				
			||||||
 | 
					      "no mgw reset-endpoint NAME",
 | 
				
			||||||
 | 
					      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
					static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -242,33 +286,36 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
 | 
				
			|||||||
	int port;
 | 
						int port;
 | 
				
			||||||
	struct reset_ep *reset_ep;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conf->description)
 | 
						/* If caller doesn't the MGW pool API (mgcp_client_pool_vty_init was never called),
 | 
				
			||||||
 | 
						 * then the "mgw" cmd prefix must be added since the old node always contained it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						const char *mgw_prefix = global_mgcp_client_pool ? "" : "mgw ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conf->description) /* description never had "mgw" prefix even on old node: */
 | 
				
			||||||
		vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
							vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = conf->local_addr;
 | 
						addr = conf->local_addr;
 | 
				
			||||||
	if (addr)
 | 
						if (addr)
 | 
				
			||||||
		vty_out(vty, "%smgw local-ip %s%s", indent, addr,
 | 
							vty_out(vty, "%s%slocal-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
				
			||||||
			VTY_NEWLINE);
 | 
					 | 
				
			||||||
	port = conf->local_port;
 | 
						port = conf->local_port;
 | 
				
			||||||
	if (port >= 0)
 | 
						if (port >= 0)
 | 
				
			||||||
		vty_out(vty, "%smgw local-port %u%s", indent,
 | 
							vty_out(vty, "%s%slocal-port %u%s", indent, mgw_prefix,
 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = conf->remote_addr;
 | 
						addr = conf->remote_addr;
 | 
				
			||||||
	if (addr)
 | 
						if (addr)
 | 
				
			||||||
		vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
 | 
							vty_out(vty, "%s%sremote-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
				
			||||||
			VTY_NEWLINE);
 | 
					 | 
				
			||||||
	port = conf->remote_port;
 | 
						port = conf->remote_port;
 | 
				
			||||||
	if (port >= 0)
 | 
						if (port >= 0)
 | 
				
			||||||
		vty_out(vty, "%smgw remote-port %u%s", indent,
 | 
							vty_out(vty, "%s%sremote-port %u%s", indent, mgw_prefix,
 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conf->endpoint_domain_name[0])
 | 
						if (conf->endpoint_domain_name[0])
 | 
				
			||||||
		vty_out(vty, "%smgw endpoint-domain %s%s", indent,
 | 
							vty_out(vty, "%s%sendpoint-domain %s%s", indent, mgw_prefix,
 | 
				
			||||||
			conf->endpoint_domain_name, VTY_NEWLINE);
 | 
								conf->endpoint_domain_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
				
			||||||
		vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
 | 
							vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -279,6 +326,11 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
 | 
				
			|||||||
 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
					 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
					int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* If caller supports MGW pool API (mgcp_client_pool_vty_init was
 | 
				
			||||||
 | 
						 * called), then skip printing any config in this node and print it when
 | 
				
			||||||
 | 
						 * the whole 'mgw' node is printed. */
 | 
				
			||||||
 | 
						if (global_mgcp_client_pool)
 | 
				
			||||||
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	return config_write(vty, indent, global_mgcp_client_conf);
 | 
						return config_write(vty, indent, global_mgcp_client_conf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -286,15 +338,15 @@ static void vty_init_common(void *talloc_ctx, int node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	global_mgcp_client_ctx = talloc_ctx;
 | 
						global_mgcp_client_ctx = talloc_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_local_ip_cmd);
 | 
						/* deprecated 'mgw' commands ('mgw' prepended as first arg) */
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_local_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_remote_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_local_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_remote_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_remote_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_remote_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_endpoint_range_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fsm_vty_add_cmds();
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -319,38 +371,62 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
 | 
				
			|||||||
	vty_init_common(talloc_ctx, node);
 | 
						vty_init_common(talloc_ctx, node);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int config_write_pool(struct vty *vty)
 | 
					/* Mark whether user called mgcp_client_pool_config_write() and hence support new API */
 | 
				
			||||||
 | 
					static bool mgcp_client_pool_config_write_called = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int _mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
						struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
 | 
						unsigned int subindent_buf_len;
 | 
				
			||||||
	char *indent = talloc_zero_size(vty, indent_buf_len);
 | 
						char *subindent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
 | 
						if (!indent)
 | 
				
			||||||
 | 
							indent = pool->vty_indent ? : "";
 | 
				
			||||||
 | 
						subindent_buf_len = strlen(indent) + 1 + 1;
 | 
				
			||||||
 | 
						subindent = talloc_zero_size(vty, subindent_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
						snprintf(subindent, subindent_buf_len, "%s ", indent);
 | 
				
			||||||
		vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
 | 
					
 | 
				
			||||||
		config_write(vty, indent, &pool_member->conf);
 | 
						llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw %u%s", indent, pool_member->nr, VTY_NEWLINE);
 | 
				
			||||||
 | 
							config_write(vty, subindent, &pool_member->conf);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(indent);
 | 
						/* MGW pool API is supported by user (global_mgcp_client_pool is set
 | 
				
			||||||
 | 
						 * because mgcp_client_pool_vty_init was called). If single MGW was
 | 
				
			||||||
 | 
						 * configured through old VTY and no mgw in the new MGW pool VTY is
 | 
				
			||||||
 | 
						 * replacing it, then output the single MGW converted to the new MGW
 | 
				
			||||||
 | 
						 * pool VTY. */
 | 
				
			||||||
 | 
						if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw 0%s", indent, VTY_NEWLINE);
 | 
				
			||||||
 | 
							config_write(vty, subindent, global_mgcp_client_conf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(subindent);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Lookup the selected MGCP client config by its reference number */
 | 
					/* Deprecated, used for backward compatibility with older users which didn't call
 | 
				
			||||||
static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
 | 
					 * mgcp_client_pool_config_write(): */
 | 
				
			||||||
 | 
					static int config_write_pool(struct vty *vty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						if (mgcp_client_pool_config_write_called)
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member_tmp;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
 | 
						return _mgcp_client_pool_config_write(vty, NULL);
 | 
				
			||||||
		if (pool_member_tmp->nr == nr) {
 | 
					}
 | 
				
			||||||
			pool_member = pool_member_tmp;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pool_member;
 | 
					/*! Write out MGCP client config to VTY.
 | 
				
			||||||
 | 
					 *  \param[in] vty VTY to which we should print.
 | 
				
			||||||
 | 
					 *  \param[in] indent string used for indentation (e.g. " ").
 | 
				
			||||||
 | 
						       If NULL, indentation passed during mgcp_client_pool_vty_init() will be used.
 | 
				
			||||||
 | 
					 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
				
			||||||
 | 
					int mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Tell internal node write function that the user supports calling proper API: */
 | 
				
			||||||
 | 
						mgcp_client_pool_config_write_called = true;
 | 
				
			||||||
 | 
						return _mgcp_client_pool_config_write(vty, indent);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_ATTR(cfg_mgw,
 | 
					DEFUN_ATTR(cfg_mgw,
 | 
				
			||||||
@@ -359,13 +435,10 @@ DEFUN_ATTR(cfg_mgw,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = pool_member_by_nr(nr);
 | 
						pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
 | 
							pool_member = mgcp_client_pool_member_alloc(global_mgcp_client_pool, nr);
 | 
				
			||||||
		OSMO_ASSERT(pool_member);
 | 
							OSMO_ASSERT(pool_member);
 | 
				
			||||||
		mgcp_client_conf_init(&pool_member->conf);
 | 
					 | 
				
			||||||
		pool_member->nr = nr;
 | 
					 | 
				
			||||||
		llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty->index = &pool_member->conf;
 | 
						vty->index = &pool_member->conf;
 | 
				
			||||||
@@ -382,7 +455,7 @@ DEFUN_ATTR(cfg_no_mgw,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = pool_member_by_nr(nr);
 | 
						pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -395,12 +468,7 @@ DEFUN_ATTR(cfg_no_mgw,
 | 
				
			|||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_del(&pool_member->list);
 | 
						mgcp_client_pool_member_free(pool_member);
 | 
				
			||||||
	if (pool_member->client) {
 | 
					 | 
				
			||||||
		mgcp_client_disconnect(pool_member->client);
 | 
					 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	talloc_free(pool_member);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -412,7 +480,7 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = pool_member_by_nr(nr);
 | 
						pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -425,32 +493,10 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
 | 
				
			|||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Get rid of a possibly existing old MGCP client instance first */
 | 
						if (mgcp_client_pool_member_reinit_client(pool_member) < 0) {
 | 
				
			||||||
	if (pool_member->client) {
 | 
					 | 
				
			||||||
		mgcp_client_disconnect(pool_member->client);
 | 
					 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create a new MGCP client instance with the current config */
 | 
					 | 
				
			||||||
	pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
					 | 
				
			||||||
	if (!pool_member->client) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
 | 
					 | 
				
			||||||
		     mgcp_client_pool_member_name(pool_member));
 | 
					 | 
				
			||||||
		vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
					 | 
				
			||||||
			mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
					 | 
				
			||||||
		return CMD_WARNING;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
					 | 
				
			||||||
	pool_member->client->pool = global_mgcp_client_pool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Connect client */
 | 
					 | 
				
			||||||
	if (mgcp_client_connect(pool_member->client)) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
 | 
				
			||||||
		     mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
 | 
							     mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
 | 
				
			||||||
		     pool_member->conf.remote_port);
 | 
							     pool_member->conf.remote_port);
 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
		pool_member->client = NULL;
 | 
					 | 
				
			||||||
		vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
							vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
				
			||||||
			mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
								mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -466,7 +512,7 @@ DEFUN_ATTR(mgw_block, mgw_block_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = pool_member_by_nr(nr);
 | 
						pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -483,7 +529,7 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = pool_member_by_nr(nr);
 | 
						pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -493,20 +539,20 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
 | 
					DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
 | 
						vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
 | 
						if (llist_empty(&global_mgcp_client_pool->member_list) && global_mgcp_client_pool->mgcp_client_single) {
 | 
				
			||||||
		vty_out(vty, "%%  (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
 | 
							vty_out(vty, "%%  (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	} else if (llist_empty(&global_mgcp_client_pool->pool)) {
 | 
						} else if (llist_empty(&global_mgcp_client_pool->member_list)) {
 | 
				
			||||||
		vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
							vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
 | 
						llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
				
			||||||
		vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
							vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
							vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
@@ -520,7 +566,8 @@ DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information abo
 | 
				
			|||||||
 *  (called once at startup by the application process).
 | 
					 *  (called once at startup by the application process).
 | 
				
			||||||
 *  \param[in] parent_node identifier of the parent node on which the mgw node appears.
 | 
					 *  \param[in] parent_node identifier of the parent node on which the mgw node appears.
 | 
				
			||||||
 *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.
 | 
					 *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.
 | 
				
			||||||
 *  \param[in] indent indentation string to match the indentation in the VTY config
 | 
					 *  \param[in] indent indentation string to match the indentation in the VTY config.
 | 
				
			||||||
 | 
						       If NULL, it must be passed explicitly each time mgcp_client_pool_config_write() is called.
 | 
				
			||||||
 *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
 | 
					 *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
 | 
				
			||||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -528,11 +575,12 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	OSMO_ASSERT(pool);
 | 
						OSMO_ASSERT(pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Never allow this function to be called twice on the same pool */
 | 
						/* Never allow this function to be called twice on the same pool */
 | 
				
			||||||
	OSMO_ASSERT(!pool->vty_indent);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(!pool->vty_node);
 | 
						OSMO_ASSERT(!pool->vty_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool->vty_indent = talloc_strdup(pool, indent);
 | 
						if (indent) {
 | 
				
			||||||
	OSMO_ASSERT(pool->vty_indent);
 | 
							pool->vty_indent = talloc_strdup(pool, indent);
 | 
				
			||||||
 | 
							OSMO_ASSERT(pool->vty_indent);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	pool->vty_node = talloc_zero(pool, struct cmd_node);
 | 
						pool->vty_node = talloc_zero(pool, struct cmd_node);
 | 
				
			||||||
	OSMO_ASSERT(pool->vty_node);
 | 
						OSMO_ASSERT(pool->vty_node);
 | 
				
			||||||
	pool->vty_node->node = mgw_node;
 | 
						pool->vty_node->node = mgw_node;
 | 
				
			||||||
@@ -542,8 +590,19 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	install_lib_element(parent_node, &cfg_mgw_cmd);
 | 
						install_lib_element(parent_node, &cfg_mgw_cmd);
 | 
				
			||||||
	install_lib_element(parent_node, &cfg_no_mgw_cmd);
 | 
						install_lib_element(parent_node, &cfg_no_mgw_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note: config_write_pool is deprecated and user is expected to
 | 
				
			||||||
 | 
						 * manually call mgcp_client_pool_config_write() when printing the VTY
 | 
				
			||||||
 | 
						 * config */
 | 
				
			||||||
	install_node(pool->vty_node, config_write_pool);
 | 
						install_node(pool->vty_node, config_write_pool);
 | 
				
			||||||
	vty_init_common(pool, mgw_node);
 | 
						vty_init_common(pool, mgw_node);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_local_ip_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_local_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_remote_ip_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_remote_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_reset_ep_name_cmd);
 | 
				
			||||||
 | 
						install_lib_element(mgw_node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_element(mgw_node, &cfg_description_cmd);
 | 
						install_element(mgw_node, &cfg_description_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -551,7 +610,7 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	install_lib_element(ENABLE_NODE, &mgw_block_cmd);
 | 
						install_lib_element(ENABLE_NODE, &mgw_block_cmd);
 | 
				
			||||||
	install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
 | 
						install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_lib_element_ve(&mgw_snow_cmd);
 | 
						install_lib_element_ve(&mgw_show_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	global_mgcp_client_pool = pool;
 | 
						global_mgcp_client_pool = pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_stat.c \
 | 
						mgcp_stat.c \
 | 
				
			||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
	mgcp_trunk.c \
 | 
						mgcp_trunk.c \
 | 
				
			||||||
	mgcp_ctrl.c \
 | 
					 | 
				
			||||||
	mgcp_ratectr.c \
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
	mgcp_e1.c \
 | 
						mgcp_e1.c \
 | 
				
			||||||
	mgcp_iuup.c \
 | 
						mgcp_iuup.c \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -345,6 +345,18 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
				
			||||||
 | 
					bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (codec->param_present == false)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (!codec->param.amr_octet_aligned_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
					/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
				
			||||||
 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
					 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
				
			||||||
 * Media Type Registration":
 | 
					 * Media Type Registration":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@
 | 
				
			|||||||
#include <osmocom/core/timer.h>
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "conn_rtp",
 | 
						.group_name_prefix = "conn_rtp",
 | 
				
			||||||
	.group_description = "rtp connection statistics",
 | 
						.group_description = "rtp connection statistics",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -95,15 +95,21 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	static atomic_uint rate_ctr_index = 0;
 | 
						static atomic_uint rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
						conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
				
			||||||
	conn_rtp->osmux.cid_allocated = false;
 | 
					
 | 
				
			||||||
	conn_rtp->osmux.cid = 0;
 | 
						/* Osmux specific defaults, only used if conn is later on Osmux-enabled: */
 | 
				
			||||||
 | 
						conn_rtp->osmux.state = OSMUX_STATE_DISABLED;
 | 
				
			||||||
 | 
						conn_rtp->osmux.local_cid_allocated = false;
 | 
				
			||||||
 | 
						conn_rtp->osmux.local_cid = 0;
 | 
				
			||||||
 | 
						conn_rtp->osmux.remote_cid_present = false;
 | 
				
			||||||
 | 
						conn_rtp->osmux.remote_cid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* backpointer to the generic part of the connection */
 | 
						/* backpointer to the generic part of the connection */
 | 
				
			||||||
	conn->u.rtp.conn = conn;
 | 
						conn->u.rtp.conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	end->rtp.fd = -1;
 | 
						end->rtp.fd = -1;
 | 
				
			||||||
	end->rtcp.fd = -1;
 | 
						end->rtcp.fd = -1;
 | 
				
			||||||
	end->rtp_port = end->rtcp_port = 0;
 | 
						memset(&end->addr, 0, sizeof(end->addr));
 | 
				
			||||||
 | 
						end->rtcp_port = 0;
 | 
				
			||||||
	talloc_free(end->fmtp_extra);
 | 
						talloc_free(end->fmtp_extra);
 | 
				
			||||||
	end->fmtp_extra = NULL;
 | 
						end->fmtp_extra = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,12 +119,12 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	end->output_enabled = false;
 | 
						end->output_enabled = false;
 | 
				
			||||||
	end->maximum_packet_time = -1;
 | 
						end->maximum_packet_time = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
						conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
 | 
				
			||||||
	if (!conn_rtp->rate_ctr_group)
 | 
						if (!conn_rtp->ctrg)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
@@ -134,7 +140,7 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			|||||||
	if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
						if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
				
			||||||
		mgcp_conn_iuup_cleanup(conn_rtp);
 | 
							mgcp_conn_iuup_cleanup(conn_rtp);
 | 
				
			||||||
	mgcp_free_rtp_port(&conn_rtp->end);
 | 
						mgcp_free_rtp_port(&conn_rtp->end);
 | 
				
			||||||
	rate_ctr_group_free(conn_rtp->rate_ctr_group);
 | 
						rate_ctr_group_free(conn_rtp->ctrg);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -263,7 +269,7 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
					static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						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->ctrg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (all_stats == NULL || conn_stats == NULL)
 | 
						if (all_stats == NULL || conn_stats == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -360,14 +366,38 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		/* Dump RTP connection */
 | 
							switch (conn->u.rtp.type) {
 | 
				
			||||||
		snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
							case MGCP_RTP_DEFAULT:
 | 
				
			||||||
			 "rtp:%u rtcp:%u)",
 | 
								/* Dump RTP connection */
 | 
				
			||||||
			 conn->name,
 | 
								snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
				
			||||||
			 conn->id,
 | 
									"rtp:%u rtcp:%u)",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
									conn->name, conn->id,
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtp_port),
 | 
									osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtcp_port));
 | 
									osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
				
			||||||
 | 
									ntohs(conn->u.rtp.end.rtcp_port));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case MGCP_RTP_OSMUX:
 | 
				
			||||||
 | 
								snprintf(str, sizeof(str), "(%s/osmux, id:0x%s, ip:%s, "
 | 
				
			||||||
 | 
									"port:%u CID:%u)",
 | 
				
			||||||
 | 
									conn->name, conn->id,
 | 
				
			||||||
 | 
									osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
				
			||||||
 | 
									osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
				
			||||||
 | 
									conn->u.rtp.osmux.local_cid);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case MGCP_RTP_IUUP:
 | 
				
			||||||
 | 
								snprintf(str, sizeof(str), "(%s/iuup, id:0x%s, ip:%s, "
 | 
				
			||||||
 | 
									"port:%u)",
 | 
				
			||||||
 | 
									conn->name, conn->id,
 | 
				
			||||||
 | 
									osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
				
			||||||
 | 
									osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								/* Should not happen, we should be able to dump
 | 
				
			||||||
 | 
								 * every possible connection type. */
 | 
				
			||||||
 | 
								snprintf(str, sizeof(str), "(unknown conn_rtp connection type %u)",
 | 
				
			||||||
 | 
									 conn->u.rtp.type);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
					 | 
				
			||||||
 * 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/ctrl/control_if.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
 | 
					 | 
				
			||||||
				void **node_data, int *i)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
					 | 
				
			||||||
					     const char *bind_addr, uint16_t port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
 | 
					 | 
				
			||||||
					   _LAST_CTRL_NODE);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -496,7 +496,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* !Equip E1 endpoint with I.460 mux resources.
 | 
					/*! Equip E1 endpoint with I.460 mux resources.
 | 
				
			||||||
 *  \param[in] endp endpoint to equip
 | 
					 *  \param[in] endp endpoint to equip
 | 
				
			||||||
 *  \param[in] ts E1 timeslot number.
 | 
					 *  \param[in] ts E1 timeslot number.
 | 
				
			||||||
 *  \param[in] ss E1 subslot number.
 | 
					 *  \param[in] ss E1 subslot number.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,7 +98,11 @@ static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t f
 | 
				
			|||||||
	uint8_t rfci_cnt = 0;
 | 
						uint8_t rfci_cnt = 0;
 | 
				
			||||||
	unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
 | 
						unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
 | 
						struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
 | 
				
			||||||
	OSMO_ASSERT(irp);
 | 
						if (!irp) {
 | 
				
			||||||
 | 
							/* No IuUP Initialization has occured on the IuUP side yet. Return error and drop the RTP data, until
 | 
				
			||||||
 | 
							 * the IuUP Initialization has configured the link. */
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: cache this somehow */
 | 
						/* TODO: cache this somehow */
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
				
			||||||
@@ -270,9 +274,9 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
		return ft;
 | 
							return ft;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msgb_pull_to_l3(msg);
 | 
						msgb_pull_to_l3(msg);
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR: ft %d, len %d\n", ft, msgb_l3len(msg));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
						if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
				
			||||||
		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
							amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
				
			||||||
		amr_hdr->cmr = 15; /* no change */
 | 
							amr_hdr->cmr = 15; /* no change */
 | 
				
			||||||
		amr_hdr->f = 0;
 | 
							amr_hdr->f = 0;
 | 
				
			||||||
@@ -291,6 +295,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg
 | 
				
			|||||||
		amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
 | 
							amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
 | 
				
			||||||
		amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
 | 
							amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
 | 
				
			||||||
		msgb_trim(msg, amr_length);
 | 
							msgb_trim(msg, amr_length);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR BE: ft %d, len %zd\n", ft, amr_length);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
 | 
						rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
 | 
				
			||||||
	*rtp_hdr = (struct rtp_hdr){
 | 
						*rtp_hdr = (struct rtp_hdr){
 | 
				
			||||||
@@ -342,8 +347,7 @@ static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osm
 | 
				
			|||||||
		return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
							return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
				
			||||||
	case MGCP_RTP_DEFAULT:
 | 
						case MGCP_RTP_DEFAULT:
 | 
				
			||||||
		return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
							return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
				
			||||||
	case MGCP_OSMUX_BSC:
 | 
						case MGCP_RTP_OSMUX:
 | 
				
			||||||
	case MGCP_OSMUX_BSC_NAT:
 | 
					 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "Forward of IuUP payload to RTP connection type %u not supported!\n",
 | 
								 "Forward of IuUP payload to RTP connection type %u not supported!\n",
 | 
				
			||||||
@@ -490,7 +494,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
			 "rtp_port:%u rtcp_port:%u\n",
 | 
								 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name,
 | 
								 dest_name,
 | 
				
			||||||
			 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
								 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -506,14 +510,13 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
						LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
		 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
							 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
		 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
							 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
		 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port));
 | 
							 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
	forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
						forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
				
			||||||
		     msg);
 | 
							     msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
 | 
						len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
 | 
				
			||||||
			    (char *)hdr, buflen);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (len <= 0)
 | 
						if (len <= 0)
 | 
				
			||||||
		return len;
 | 
							return len;
 | 
				
			||||||
@@ -618,9 +621,8 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
 | 
				
			|||||||
		force_output_enabled = true;
 | 
							force_output_enabled = true;
 | 
				
			||||||
		/* Fill in the peer address so that we can send Init-ACK back: */
 | 
							/* Fill in the peer address so that we can send Init-ACK back: */
 | 
				
			||||||
		prev_rem_addr = conn_rtp_src->end.addr;
 | 
							prev_rem_addr = conn_rtp_src->end.addr;
 | 
				
			||||||
		prev_rem_rtp_port = conn_rtp_src->end.rtp_port;
 | 
							prev_rem_rtp_port = osmo_sockaddr_port(&conn_rtp_src->end.addr.u.sa);
 | 
				
			||||||
		conn_rtp_src->end.addr = *mc->from_addr;
 | 
							conn_rtp_src->end.addr = *mc->from_addr;
 | 
				
			||||||
		conn_rtp_src->end.rtp_port = htons(osmo_sockaddr_port(&mc->from_addr->u.sa));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
 | 
						rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
 | 
				
			||||||
@@ -628,7 +630,7 @@ int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
 | 
				
			|||||||
	if (force_output_enabled) {
 | 
						if (force_output_enabled) {
 | 
				
			||||||
		conn_rtp_src->end.output_enabled = prev_output_enabled;
 | 
							conn_rtp_src->end.output_enabled = prev_output_enabled;
 | 
				
			||||||
		conn_rtp_src->end.addr = prev_rem_addr;
 | 
							conn_rtp_src->end.addr = prev_rem_addr;
 | 
				
			||||||
		conn_rtp_src->end.rtp_port = prev_rem_rtp_port;
 | 
							osmo_sockaddr_set_port(&conn_rtp_src->end.addr.u.sa, prev_rem_rtp_port);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
@@ -670,7 +672,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
				
			|||||||
				     "Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
 | 
									     "Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (amr_hdr->ft >= AMR_FT_MAX) {
 | 
							if (!osmo_amr_ft_valid(amr_hdr->ft)) {
 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -678,19 +680,22 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
				
			|||||||
			LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
 | 
								LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		irp->u.data.fqc = amr_hdr->q;
 | 
							irp->u.data.fqc = amr_hdr->q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
				
			||||||
		irp->u.data.rfci = rfci;
 | 
							irp->u.data.rfci = rfci;
 | 
				
			||||||
		msgb_pull(msg, 2);
 | 
							msgb_pull(msg, 2);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR OA -> IuUP: ft %d -> rfci %d len %d\n",
 | 
				
			||||||
 | 
							     amr_hdr->ft, rfci, msgb_length(msg));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
 | 
							uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
 | 
				
			||||||
		int8_t ft;
 | 
							int8_t ft;
 | 
				
			||||||
 | 
							uint8_t q;
 | 
				
			||||||
		if (msgb_length(msg) < 2) {
 | 
							if (msgb_length(msg) < 2) {
 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
				
			||||||
				     "Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
 | 
									     "Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
 | 
							ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
 | 
				
			||||||
		if (ft >= AMR_FT_MAX) {
 | 
							if (!osmo_amr_ft_valid(ft)) {
 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
 | 
								LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -698,7 +703,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
				
			|||||||
			LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
 | 
								LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
 | 
				
			||||||
			goto free_ret;
 | 
								goto free_ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		irp->u.data.fqc = ((amr_bwe_hdr[1] & 0x40) >> 6);
 | 
							q = amr_bwe_hdr[1] & 0x40;
 | 
				
			||||||
 | 
							irp->u.data.fqc = q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
				
			||||||
		irp->u.data.rfci = rfci;
 | 
							irp->u.data.rfci = rfci;
 | 
				
			||||||
		rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
 | 
							rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
		if (rc < 0) {
 | 
							if (rc < 0) {
 | 
				
			||||||
@@ -706,6 +712,8 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn
 | 
				
			|||||||
			return rc;
 | 
								return rc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		msgb_trim(msg, iuup_length);
 | 
							msgb_trim(msg, iuup_length);
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR BE -> IuUP: ft %d -> rfci %d len %d\n",
 | 
				
			||||||
 | 
							     ft, rfci, msgb_length(msg));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
 | 
						irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -202,7 +202,7 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return osmux_cid;
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,15 +54,10 @@
 | 
				
			|||||||
#define RTP_MAX_DROPOUT		3000
 | 
					#define RTP_MAX_DROPOUT		3000
 | 
				
			||||||
#define RTP_MAX_MISORDER	100
 | 
					#define RTP_MAX_MISORDER	100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum rtp_proto {
 | 
					 | 
				
			||||||
	MGCP_PROTO_RTP,
 | 
					 | 
				
			||||||
	MGCP_PROTO_RTCP,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
				 int id, int inc)
 | 
									 int id, int inc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
						struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
 | 
				
			||||||
	struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add to both the per-connection and the global stats */
 | 
						/* add to both the per-connection and the global stats */
 | 
				
			||||||
@@ -70,49 +65,68 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
 | 
				
			|||||||
	rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
 | 
					void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
						rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rx_rtp(struct msgb *msg);
 | 
					static int rx_rtp(struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool addr_is_any(const struct osmo_sockaddr *osa)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (osa->u.sa.sa_family == AF_INET6) {
 | 
					 | 
				
			||||||
		struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
 | 
					 | 
				
			||||||
		return memcmp(&osa->u.sin6.sin6_addr,
 | 
					 | 
				
			||||||
				   &ip6_any, sizeof(ip6_any)) == 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return osa->u.sin.sin_addr.s_addr == 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return rtp_end->rtp_port && !addr_is_any(&rtp_end->addr);
 | 
						return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
				
			||||||
 | 
						       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Determine the local rtp bind IP-address.
 | 
					/*! Determine the local rtp bind IP-address.
 | 
				
			||||||
 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
					 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
				
			||||||
 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
					 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
				
			||||||
 | 
					 * \ returns 0 on success, -1 if no local address could be provided.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  The local bind IP-address is automatically selected by probing the
 | 
					 *  The local bind IP-address is automatically selected by probing the
 | 
				
			||||||
 *  IP-Address of the interface that is pointing towards the remote IP-Address,
 | 
					 *  IP-Address of the interface that is pointing towards the remote IP-Address,
 | 
				
			||||||
 *  if no remote IP-Address is known yet, the statically configured
 | 
					 *  if no remote IP-Address is known yet, the statically configured
 | 
				
			||||||
 *  IP-Addresses are used as fallback. */
 | 
					 *  IP-Addresses are used as fallback. */
 | 
				
			||||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
					int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_endpoint *endp = conn->conn->endp;
 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
						const struct mgcp_config *cfg = endp->trunk->cfg;
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	endp = conn->conn->endp;
 | 
						bool rem_addr_set = osmo_sockaddr_is_any(&conn->end.addr) == 0;
 | 
				
			||||||
	bool rem_addr_set = !addr_is_any(&conn->end.addr);
 | 
						const char *bind_addr;
 | 
				
			||||||
	char *bind_addr;
 | 
					
 | 
				
			||||||
 | 
						/* Osmux: No smart IP addresses allocation is supported yet. Simply
 | 
				
			||||||
 | 
						 * return the one set in VTY config: */
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
 | 
							if (rem_addr_set) {
 | 
				
			||||||
 | 
								/* Match IP version with what was requested from remote: */
 | 
				
			||||||
 | 
								bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
				
			||||||
 | 
									    cfg->osmux.local_addr_v6 :
 | 
				
			||||||
 | 
									    cfg->osmux.local_addr_v4;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								/* Choose any of the bind addresses, preferring v6 over v4 if available: */
 | 
				
			||||||
 | 
								bind_addr = cfg->osmux.local_addr_v6;
 | 
				
			||||||
 | 
								if (!bind_addr)
 | 
				
			||||||
 | 
									bind_addr = cfg->osmux.local_addr_v4;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!bind_addr) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
 | 
				
			||||||
 | 
									"Unable to locate local Osmux address, check your configuration! v4=%u v6=%u remote_known=%s\n",
 | 
				
			||||||
 | 
									!!cfg->osmux.local_addr_v4,
 | 
				
			||||||
 | 
									!!cfg->osmux.local_addr_v6,
 | 
				
			||||||
 | 
									rem_addr_set ? osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf) : "no");
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							LOGPCONN(conn->conn, DOSMUX, LOGL_DEBUG,
 | 
				
			||||||
 | 
								 "Using configured osmux bind ip as local bind ip %s\n",
 | 
				
			||||||
 | 
								 bind_addr);
 | 
				
			||||||
 | 
							osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Try probing the local IP-Address */
 | 
						/* Try probing the local IP-Address */
 | 
				
			||||||
	if (endp->trunk->cfg->net_ports.bind_addr_probe && rem_addr_set) {
 | 
						if (cfg->net_ports.bind_addr_probe && rem_addr_set) {
 | 
				
			||||||
		rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
							rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
@@ -121,22 +135,22 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
			LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
								LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
				 "selected local rtp bind ip %s by probing using remote ip %s\n",
 | 
									 "selected local rtp bind ip %s by probing using remote ip %s\n",
 | 
				
			||||||
				 addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
									 addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
				
			||||||
			return;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
 | 
						/* Select from preconfigured IP-Addresses. */
 | 
				
			||||||
	if (rem_addr_set) {
 | 
						if (rem_addr_set) {
 | 
				
			||||||
		/* Check there is a bind IP for the RTP traffic configured,
 | 
							/* Check there is a bind IP for the RTP traffic configured,
 | 
				
			||||||
		 * if so, use that IP-Address */
 | 
							 * if so, use that IP-Address */
 | 
				
			||||||
		bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
							bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
				
			||||||
				endp->trunk->cfg->net_ports.bind_addr_v6 :
 | 
									cfg->net_ports.bind_addr_v6 :
 | 
				
			||||||
				endp->trunk->cfg->net_ports.bind_addr_v4;
 | 
									cfg->net_ports.bind_addr_v4;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Choose any of the bind addresses, preferring v6 over v4 */
 | 
							/* Choose any of the bind addresses, preferring v6 over v4 */
 | 
				
			||||||
		bind_addr = endp->trunk->cfg->net_ports.bind_addr_v6;
 | 
							bind_addr = cfg->net_ports.bind_addr_v6;
 | 
				
			||||||
		if (!strlen(bind_addr))
 | 
							if (!strlen(bind_addr))
 | 
				
			||||||
			bind_addr = endp->trunk->cfg->net_ports.bind_addr_v4;
 | 
								bind_addr = cfg->net_ports.bind_addr_v4;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strlen(bind_addr)) {
 | 
						if (strlen(bind_addr)) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
@@ -146,11 +160,12 @@ void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		/* No specific bind IP is configured for the RTP traffic, so
 | 
							/* No specific bind IP is configured for the RTP traffic, so
 | 
				
			||||||
		 * assume the IP where we listen for incoming MGCP messages
 | 
							 * assume the IP where we listen for incoming MGCP messages
 | 
				
			||||||
		 * as bind IP */
 | 
							 * as bind IP */
 | 
				
			||||||
		bind_addr = endp->trunk->cfg->source_addr;
 | 
							bind_addr = cfg->source_addr;
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
 | 
								"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
						osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This does not need to be a precision timestamp and
 | 
					/* This does not need to be a precision timestamp and
 | 
				
			||||||
@@ -676,7 +691,7 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR, "RTP packet too short (%d < %zu)\n",
 | 
				
			||||||
			 msgb_length(msg), sizeof(struct rtp_hdr));
 | 
								 msgb_length(msg), sizeof(struct rtp_hdr));
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -702,11 +717,18 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
 | 
					/*! Convert msg to AMR RTP framing mode specified by target_is_oa.
 | 
				
			||||||
 | 
					 *  \param[in] endp MGCP Endpoint where this message belongs to (used for logging purposes)
 | 
				
			||||||
 | 
					 *  \param[in] msg Message containing an AMR RTP payload (in octet-aligned or bandwidth-efficient format).
 | 
				
			||||||
 | 
					 *  \param[in] target_is_oa the target framing mode that msg will contain after this function succeeds.
 | 
				
			||||||
 | 
					 *  \returns The size of the new RTP AMR content on success, negative on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For AMR RTP two framing modes are defined RFC3267. There is a bandwidth
 | 
				
			||||||
 * efficient encoding scheme where all fields are packed together one after
 | 
					 * efficient encoding scheme where all fields are packed together one after
 | 
				
			||||||
 * another and an octet aligned mode where all fields are aligned to octet
 | 
					 * another and an octet aligned mode where all fields are aligned to octet
 | 
				
			||||||
 * boundaries. This function is used to convert between the two modes */
 | 
					 * boundaries. This function is used to convert between the two modes.
 | 
				
			||||||
static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
					 */
 | 
				
			||||||
 | 
					int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			||||||
			      bool target_is_oa)
 | 
								      bool target_is_oa)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
 | 
						/* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
 | 
				
			||||||
@@ -715,6 +737,7 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	unsigned int payload_len;
 | 
						unsigned int payload_len;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						bool orig_is_oa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
 | 
				
			||||||
@@ -722,10 +745,10 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
 | 
						payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
						orig_is_oa = osmo_amr_is_oa(rtp_hdr->data, payload_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
 | 
						if (orig_is_oa) {
 | 
				
			||||||
		if (!target_is_oa)
 | 
							if (!target_is_oa)
 | 
				
			||||||
			/* Input data is oa an target format is bwe
 | 
								/* Input data is oa an target format is bwe
 | 
				
			||||||
			 * ==> convert */
 | 
								 * ==> convert */
 | 
				
			||||||
@@ -747,27 +770,16 @@ static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "AMR RTP packet conversion failed\n");
 | 
								 "RTP AMR packet conversion %s->%s failed: %s\n",
 | 
				
			||||||
 | 
								 orig_is_oa ? "OA" : "BWE",
 | 
				
			||||||
 | 
								 target_is_oa ? "OA" : "BWE",
 | 
				
			||||||
 | 
								 osmo_hexdump(rtp_hdr->data, payload_len));
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
 | 
						return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if a conversion between octet-aligned and bandwith-efficient mode is
 | 
					 | 
				
			||||||
 * indicated. */
 | 
					 | 
				
			||||||
static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (codec->param_present == false)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (!codec->param.amr_octet_aligned_present)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
 | 
					/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
 | 
				
			||||||
 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
 | 
					 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
 | 
				
			||||||
static int amr_oa_check(char *data, int len)
 | 
					static int amr_oa_check(char *data, int len)
 | 
				
			||||||
@@ -826,7 +838,7 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (addr_is_any(&conn->end.addr)) {
 | 
						if (osmo_sockaddr_is_any(&conn->end.addr) != 0) {
 | 
				
			||||||
		switch (conn->conn->mode) {
 | 
							switch (conn->conn->mode) {
 | 
				
			||||||
		case MGCP_CONN_LOOPBACK:
 | 
							case MGCP_CONN_LOOPBACK:
 | 
				
			||||||
			/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
 | 
								/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
 | 
				
			||||||
@@ -875,14 +887,14 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
	 * the same as the remote port where we transmit outgoing RTP traffic
 | 
						 * the same as the remote port where we transmit outgoing RTP traffic
 | 
				
			||||||
	 * to (set by MDCX). We use this to check the origin of the data for
 | 
						 * to (set by MDCX). We use this to check the origin of the data for
 | 
				
			||||||
	 * plausibility. */
 | 
						 * plausibility. */
 | 
				
			||||||
	if (ntohs(conn->end.rtp_port) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
						if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
				
			||||||
	    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
						    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "data from wrong source port: %d, ",
 | 
								 "data from wrong source port: %d, ",
 | 
				
			||||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
								 osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
		LOGPC(DRTP, LOGL_ERROR,
 | 
							LOGPC(DRTP, LOGL_ERROR,
 | 
				
			||||||
		      "expected: %d for RTP or %d for RTCP\n",
 | 
							      "expected: %d for RTP or %d for RTCP\n",
 | 
				
			||||||
		      ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
 | 
							      osmo_sockaddr_port(&conn->end.addr.u.sa), ntohs(conn->end.rtcp_port));
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -895,28 +907,29 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
static int check_rtp_destin(struct mgcp_conn_rtp *conn)
 | 
					static int check_rtp_destin(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	bool ip_is_any = addr_is_any(&conn->end.addr);
 | 
						bool ip_is_any = osmo_sockaddr_is_any(&conn->end.addr) != 0;
 | 
				
			||||||
 | 
						uint16_t port = osmo_sockaddr_port(&conn->end.addr.u.sa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: it is legal to create a connection but never setting a port
 | 
						/* Note: it is legal to create a connection but never setting a port
 | 
				
			||||||
	 * and IP-address for outgoing data. */
 | 
						 * and IP-address for outgoing data. */
 | 
				
			||||||
	if (ip_is_any && conn->end.rtp_port == 0) {
 | 
						if (ip_is_any && port == 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "destination IP-address and rtp port is not (yet) known (%s:%u)\n",
 | 
								 "destination IP-address and rtp port is not (yet) known (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ip_is_any) {
 | 
						if (ip_is_any) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "destination IP-address is invalid (%s:%u)\n",
 | 
								 "destination IP-address is invalid (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->end.rtp_port == 0) {
 | 
						if (port == 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "destination rtp port is invalid (%s:%u)\n",
 | 
								 "destination rtp port is invalid (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -980,9 +993,16 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send RTP data. Possible options are standard RTP packet
 | 
					/*! Dispatch msg bridged from the sister conn in the endpoint.
 | 
				
			||||||
 * transmission or trsmission via an osmux connection */
 | 
					 *  \param[in] conn_dst The destination conn that should handle and transmit the content to
 | 
				
			||||||
static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
					 *			its peer outside MGW.
 | 
				
			||||||
 | 
					 *  \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
 | 
				
			||||||
 | 
					 *  \returns bytes sent, -1 on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Possible options are standard RTP packet transmission, transmission
 | 
				
			||||||
 | 
					 * via IuUP or transmission via an osmux connection.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
	enum rtp_proto proto = mc->proto;
 | 
						enum rtp_proto proto = mc->proto;
 | 
				
			||||||
@@ -1007,12 +1027,11 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			|||||||
			 "using mgcp_send() to forward data directly\n");
 | 
								 "using mgcp_send() to forward data directly\n");
 | 
				
			||||||
		return mgcp_send(endp, proto == MGCP_PROTO_RTP,
 | 
							return mgcp_send(endp, proto == MGCP_PROTO_RTP,
 | 
				
			||||||
				 mc->from_addr, msg, conn_src, conn_dst);
 | 
									 mc->from_addr, msg, conn_src, conn_dst);
 | 
				
			||||||
	case MGCP_OSMUX_BSC_NAT:
 | 
						case MGCP_RTP_OSMUX:
 | 
				
			||||||
	case MGCP_OSMUX_BSC:
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "endpoint type is MGCP_OSMUX_BSC_NAT, "
 | 
								 "endpoint type is MGCP_RTP_OSMUX, "
 | 
				
			||||||
			 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
 | 
								 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
 | 
				
			||||||
		return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
 | 
							return conn_osmux_send_rtp(conn_dst, msg);
 | 
				
			||||||
	case MGCP_RTP_IUUP:
 | 
						case MGCP_RTP_IUUP:
 | 
				
			||||||
		if (proto == MGCP_PROTO_RTP) {
 | 
							if (proto == MGCP_PROTO_RTP) {
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
								LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
@@ -1039,26 +1058,22 @@ static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			|||||||
/*! send udp packet.
 | 
					/*! send udp packet.
 | 
				
			||||||
 *  \param[in] fd associated file descriptor.
 | 
					 *  \param[in] fd associated file descriptor.
 | 
				
			||||||
 *  \param[in] addr destination ip-address.
 | 
					 *  \param[in] addr destination ip-address.
 | 
				
			||||||
 *  \param[in] port destination UDP port (network byte order).
 | 
					 | 
				
			||||||
 *  \param[in] buf buffer that holds the data to be send.
 | 
					 *  \param[in] buf buffer that holds the data to be send.
 | 
				
			||||||
 *  \param[in] len length of the data to be sent.
 | 
					 *  \param[in] len length of the data to be sent.
 | 
				
			||||||
 *  \returns bytes sent, -1 on error. */
 | 
					 *  \returns bytes sent, -1 on error. */
 | 
				
			||||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len)
 | 
					int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	size_t addr_len;
 | 
						size_t addr_len;
 | 
				
			||||||
	bool is_ipv6 =  addr->u.sa.sa_family == AF_INET6;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRTP, LOGL_DEBUG,
 | 
						LOGP(DRTP, LOGL_DEBUG,
 | 
				
			||||||
	     "sending %i bytes length packet to %s:%u ...\n", len,
 | 
						     "sending %i bytes length packet to %s:%u ...\n", len,
 | 
				
			||||||
	     osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
						     osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
				
			||||||
	     ntohs(port));
 | 
						     osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_ipv6) {
 | 
						if (addr->u.sa.sa_family == AF_INET6) {
 | 
				
			||||||
		addr->u.sin6.sin6_port = port;
 | 
					 | 
				
			||||||
		addr_len = sizeof(addr->u.sin6);
 | 
							addr_len = sizeof(addr->u.sin6);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		addr->u.sin.sin_port = port;
 | 
					 | 
				
			||||||
		addr_len = sizeof(addr->u.sin);
 | 
							addr_len = sizeof(addr->u.sin);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1073,6 +1088,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	int was_rtcp = 0;
 | 
						int was_rtcp = 0;
 | 
				
			||||||
 | 
						struct osmo_sockaddr rtcp_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
@@ -1089,7 +1105,7 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	if (mgcp_conn_rtp_is_iuup(conn))
 | 
						if (mgcp_conn_rtp_is_iuup(conn))
 | 
				
			||||||
		rc = mgcp_conn_iuup_send_dummy(conn);
 | 
							rc = mgcp_conn_iuup_send_dummy(conn);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr, conn->end.rtp_port,
 | 
							rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
 | 
				
			||||||
				   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
									   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc == -1)
 | 
						if (rc == -1)
 | 
				
			||||||
@@ -1099,8 +1115,10 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	was_rtcp = 1;
 | 
						was_rtcp = 1;
 | 
				
			||||||
	rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
 | 
						rtcp_addr = conn->end.addr;
 | 
				
			||||||
			   conn->end.rtcp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
						osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
 | 
				
			||||||
 | 
						rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
 | 
				
			||||||
 | 
								   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc >= 0)
 | 
						if (rc >= 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
@@ -1146,17 +1164,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: It is legal that the payload type on the egress connection is
 | 
						/* Patch the payload type number: translate from conn_src to conn_dst.
 | 
				
			||||||
	 * different from the payload type that has been negotiated on the
 | 
						 * Do not patch for IuUP, where the correct payload type number is already set in bridge_iuup_to_rtp_peer():
 | 
				
			||||||
	 * ingress connection. Essentially the codecs are the same so we can
 | 
						 * IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
 | 
				
			||||||
	 * match them and patch the payload type. However, if we can not find
 | 
						 * {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
 | 
				
			||||||
	 * the codec pendant (everything ist equal except the PT), we are of
 | 
						if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
				
			||||||
	 * course unable to patch the payload type. A situation like this
 | 
					 | 
				
			||||||
	 * should not occur if transcoding is consequently avoided. Until
 | 
					 | 
				
			||||||
	 * we have transcoding support in osmo-mgw we can not resolve this. */
 | 
					 | 
				
			||||||
	if (is_rtp && conn_dst->type != MGCP_RTP_IUUP) {
 | 
					 | 
				
			||||||
		rc = mgcp_patch_pt(conn_src, conn_dst, msg);
 | 
							rc = mgcp_patch_pt(conn_src, conn_dst, msg);
 | 
				
			||||||
		if (rc < 0) {
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								/* FIXME: It is legal that the payload type on the egress connection is
 | 
				
			||||||
 | 
								 * different from the payload type that has been negotiated on the
 | 
				
			||||||
 | 
								 * ingress connection. Essentially the codecs are the same so we can
 | 
				
			||||||
 | 
								 * match them and patch the payload type. However, if we can not find
 | 
				
			||||||
 | 
								 * the codec pendant (everything ist equal except the PT), we are of
 | 
				
			||||||
 | 
								 * course unable to patch the payload type. A situation like this
 | 
				
			||||||
 | 
								 * should not occur if transcoding is consequently avoided. Until
 | 
				
			||||||
 | 
								 * we have transcoding support in osmo-mgw we can not resolve this. */
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
								LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
				 "can not patch PT because no suitable egress codec was found.\n");
 | 
									 "can not patch PT because no suitable egress codec was found.\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1180,7 +1202,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
			 "rtp_port:%u rtcp_port:%u\n",
 | 
								 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name,
 | 
								 dest_name,
 | 
				
			||||||
			 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
								 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
		    );
 | 
							    );
 | 
				
			||||||
	} else if (is_rtp) {
 | 
						} else if (is_rtp) {
 | 
				
			||||||
		int cont;
 | 
							int cont;
 | 
				
			||||||
@@ -1203,12 +1225,13 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
								if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
				
			||||||
				/* the iuup code will correctly transform to the correct AMR mode */
 | 
									/* the iuup code will correctly transform to the correct AMR mode */
 | 
				
			||||||
			} else if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
 | 
								} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
 | 
				
			||||||
				rc = amr_oa_bwe_convert(endp, msg,
 | 
									rc = amr_oa_bwe_convert(endp, msg,
 | 
				
			||||||
							conn_dst->end.codec->param.amr_octet_aligned);
 | 
												conn_dst->end.codec->param.amr_octet_aligned);
 | 
				
			||||||
				if (rc < 0) {
 | 
									if (rc < 0) {
 | 
				
			||||||
					LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
										LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
				
			||||||
						 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
 | 
											 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
 | 
				
			||||||
 | 
											 conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if (rtp_end->rfc5993_hr_convert &&
 | 
								} else if (rtp_end->rfc5993_hr_convert &&
 | 
				
			||||||
@@ -1225,14 +1248,14 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
				 "rtp_port:%u rtcp_port:%u\n",
 | 
									 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
				 dest_name,
 | 
									 dest_name,
 | 
				
			||||||
				 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
									 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
				 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
									 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Forward a copy of the RTP data to a debug ip/port */
 | 
								/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
			forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
								forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
				
			||||||
				     msg);
 | 
									     msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
 | 
								len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
 | 
				
			||||||
					    (char *)msgb_data(msg), msgb_length(msg));
 | 
										    (char *)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (len <= 0)
 | 
								if (len <= 0)
 | 
				
			||||||
@@ -1247,15 +1270,17 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
		} while (buflen > 0);
 | 
							} while (buflen > 0);
 | 
				
			||||||
		return nbytes;
 | 
							return nbytes;
 | 
				
			||||||
	} else if (!trunk->omit_rtcp) {
 | 
						} else if (!trunk->omit_rtcp) {
 | 
				
			||||||
 | 
							struct osmo_sockaddr rtcp_addr = rtp_end->addr;
 | 
				
			||||||
 | 
							osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
								 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
								 dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
 | 
				
			||||||
			 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
								 osmo_sockaddr_port(&rtp_end->addr.u.sa),
 | 
				
			||||||
 | 
								 osmo_sockaddr_port(&rtcp_addr.u.sa)
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		len = mgcp_udp_send(rtp_end->rtcp.fd,
 | 
							len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
 | 
				
			||||||
				    &rtp_end->addr,
 | 
									    (char *)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
				    rtp_end->rtcp_port, (char *)msgb_data(msg), msgb_length(msg));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
							rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
		rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
							rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
				
			||||||
@@ -1267,13 +1292,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dispatch incoming RTP packet to opposite RTP connection.
 | 
					/*! Dispatch incoming RTP packet to opposite RTP connection.
 | 
				
			||||||
 *  \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP).
 | 
					 * \param[in] msg Message buffer to bridge, coming from source connection.
 | 
				
			||||||
 *  \param[in] addr socket address where the RTP packet has been received from.
 | 
					 *            msg shall contain "struct osmo_rtp_msg_ctx *" attached in
 | 
				
			||||||
 *  \param[in] buf buffer that hold the RTP payload.
 | 
					 *            "OSMO_RTP_MSG_CTX(msg)".
 | 
				
			||||||
 *  \param[in] buf_size size data length of buf.
 | 
					 *  \returns 0 on success, -1 on ERROR.
 | 
				
			||||||
 *  \param[in] conn originating connection.
 | 
					 */
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
					 | 
				
			||||||
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
					int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
@@ -1302,25 +1326,15 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (conn->u.rtp.end.rtp_port == 0) {
 | 
							if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn->u.rtp.end.addr));
 | 
				
			||||||
			switch (from_addr->u.sa.sa_family) {
 | 
					 | 
				
			||||||
			case AF_INET:
 | 
					 | 
				
			||||||
				conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case AF_INET6:
 | 
					 | 
				
			||||||
				conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				OSMO_ASSERT(false);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     conn->u.rtp.end.rtp_port);
 | 
									     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_send_rtp(conn_src, msg);
 | 
							return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find a destination connection. */
 | 
						/* Find a destination connection. */
 | 
				
			||||||
@@ -1352,7 +1366,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Dispatch RTP packet to destination RTP connection */
 | 
						/* Dispatch RTP packet to destination RTP connection */
 | 
				
			||||||
	return mgcp_send_rtp(&conn_dst->u.rtp, msg);
 | 
						return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
					/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
				
			||||||
@@ -1377,25 +1391,15 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (conn->u.rtp.end.rtp_port == 0) {
 | 
							if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn->u.rtp.end.addr));
 | 
				
			||||||
			switch (from_addr->u.sa.sa_family) {
 | 
					 | 
				
			||||||
			case AF_INET:
 | 
					 | 
				
			||||||
				conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			case AF_INET6:
 | 
					 | 
				
			||||||
				conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				OSMO_ASSERT(false);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     conn->u.rtp.end.rtp_port);
 | 
									     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_send_rtp(conn_src, msg);
 | 
							return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward to E1 */
 | 
						/* Forward to E1 */
 | 
				
			||||||
@@ -1504,8 +1508,8 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
					sizeof(struct sockaddr_in)));
 | 
										sizeof(struct sockaddr_in)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Increment RX statistics */
 | 
						/* Increment RX statistics */
 | 
				
			||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_PACKETS_RX_CTR));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_PACKETS_RX_CTR));
 | 
				
			||||||
	rate_ctr_add(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_OCTETS_RX_CTR), msgb_length(msg));
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_OCTETS_RX_CTR), msgb_length(msg));
 | 
				
			||||||
	/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
						/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
@@ -1529,25 +1533,29 @@ static int rx_rtp(struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
 | 
						LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_conn_watchdog_kick(conn_src->conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If AMR is configured for the ingress connection a conversion of the
 | 
					 | 
				
			||||||
	 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
 | 
					 | 
				
			||||||
	 * define, then we check if the incoming payload matches that
 | 
					 | 
				
			||||||
	 * expectation. */
 | 
					 | 
				
			||||||
	if (mc->proto == MGCP_PROTO_RTP &&
 | 
					 | 
				
			||||||
	    amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
 | 
					 | 
				
			||||||
		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
					 | 
				
			||||||
		if (oa < 0)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Check if the origin of the RTP packet seems plausible */
 | 
						/* Check if the origin of the RTP packet seems plausible */
 | 
				
			||||||
	if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
						if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */
 | 
				
			||||||
 | 
						if (mc->proto == MGCP_PROTO_RTP &&
 | 
				
			||||||
 | 
						    mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
 | 
				
			||||||
 | 
							/* Make sure that the incoming AMR frame format matches the frame format that the call agent has
 | 
				
			||||||
 | 
							 * communicated via SDP when the connection was created/modfied. */
 | 
				
			||||||
 | 
							int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
							if (oa < 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
 | 
				
			||||||
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
 | 
									     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
 | 
				
			||||||
 | 
									     " check the config of your call-agent!\n",
 | 
				
			||||||
 | 
									     msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_watchdog_kick(conn_src->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Execute endpoint specific implementation that handles the
 | 
						/* Execute endpoint specific implementation that handles the
 | 
				
			||||||
	 * dispatching of the RTP data */
 | 
						 * dispatching of the RTP data */
 | 
				
			||||||
	return conn->endp->type->dispatch_rtp_cb(msg);
 | 
						return conn->endp->type->dispatch_rtp_cb(msg);
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -47,6 +47,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_iuup.h>
 | 
					#include <osmocom/mgcp/mgcp_iuup.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Contains the last successfully resolved endpoint name. This variable is used
 | 
					/* Contains the last successfully resolved endpoint name. This variable is used
 | 
				
			||||||
 * for the unit-tests to verify that the endpoint was correctly resolved. */
 | 
					 * for the unit-tests to verify that the endpoint was correctly resolved. */
 | 
				
			||||||
@@ -150,8 +151,7 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_RTP_DEFAULT:
 | 
						case MGCP_RTP_DEFAULT:
 | 
				
			||||||
	case MGCP_OSMUX_BSC:
 | 
						case MGCP_RTP_OSMUX:
 | 
				
			||||||
	case MGCP_OSMUX_BSC_NAT:
 | 
					 | 
				
			||||||
	case MGCP_RTP_IUUP:
 | 
						case MGCP_RTP_IUUP:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -301,7 +301,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Attach optional OSMUX parameters */
 | 
						/* Attach optional OSMUX parameters */
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "X-Osmux: %u\r\n", conn->osmux.cid);
 | 
							rc = msgb_printf(sdp, MGCP_X_OSMO_OSMUX_HEADER " %u\r\n", conn->osmux.local_cid);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -324,8 +324,13 @@ error:
 | 
				
			|||||||
 * osmux connection, send the dummy packet via OSMUX */
 | 
					 * osmux connection, send the dummy packet via OSMUX */
 | 
				
			||||||
static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (conn->osmux.state != OSMUX_STATE_DISABLED)
 | 
						/* Avoid sending dummy packet if the remote address was not yet
 | 
				
			||||||
		osmux_send_dummy(endp, conn);
 | 
						 * configured through CRCX/MDCX: */
 | 
				
			||||||
 | 
						if (!mgcp_rtp_end_remote_addr_available(&conn->end))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn))
 | 
				
			||||||
 | 
							osmux_send_dummy(conn);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		mgcp_send_dummy(endp, conn);
 | 
							mgcp_send_dummy(endp, conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -709,7 +714,7 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	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",
 | 
				
			||||||
		 ntohs(rtp->rtp_port),
 | 
							 osmo_sockaddr_port(&rtp->addr.u.sa),
 | 
				
			||||||
		 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
							 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
				
			||||||
		 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
 | 
							 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -740,12 +745,12 @@ uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
 | 
					static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!endp->trunk->cfg->osmux_init) {
 | 
						if (!endp->trunk->cfg->osmux.initialized) {
 | 
				
			||||||
		if (osmux_init(OSMUX_ROLE_BSC, endp->trunk->cfg) < 0) {
 | 
							if (osmux_init(endp->trunk) < 0) {
 | 
				
			||||||
			LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
								LOGPENDP(endp, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
				
			||||||
			return -3;
 | 
								return -3;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
 | 
							LOGPENDP(endp, DOSMUX, LOGL_NOTICE, "OSMUX socket has been set up\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_parse_osmux_cid(line);
 | 
						return mgcp_parse_osmux_cid(line);
 | 
				
			||||||
@@ -846,7 +851,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	const char *callid = NULL;
 | 
						const char *callid = NULL;
 | 
				
			||||||
	const char *mode = NULL;
 | 
						const char *mode = NULL;
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	int have_sdp = 0, osmux_cid = -2;
 | 
						int have_sdp = 0, remote_osmux_cid = -2;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
	struct mgcp_conn *_conn = NULL;
 | 
						struct mgcp_conn *_conn = NULL;
 | 
				
			||||||
	char conn_name[512];
 | 
						char conn_name[512];
 | 
				
			||||||
@@ -893,9 +898,9 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		case 'X':
 | 
							case 'X':
 | 
				
			||||||
			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
				/* If osmux is disabled, just skip setting it up */
 | 
									/* If osmux is disabled, just skip setting it up */
 | 
				
			||||||
				if (!rq->endp->trunk->cfg->osmux)
 | 
									if (rq->endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				osmux_cid = mgcp_osmux_setup(endp, line);
 | 
									remote_osmux_cid = mgcp_osmux_setup(endp, line);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -998,16 +1003,17 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Annotate Osmux circuit ID and set it to negotiating state until this
 | 
						/* If X-Osmux (remote CID) was received (-1 is wilcard), alloc next avail CID as local CID */
 | 
				
			||||||
	 * is fully set up from the dummy load. */
 | 
						if (remote_osmux_cid >= -1) {
 | 
				
			||||||
	conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
							if (osmux_init_conn(conn) < 0) {
 | 
				
			||||||
	if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
 | 
					 | 
				
			||||||
		conn->osmux.state = OSMUX_STATE_ACTIVATING;
 | 
					 | 
				
			||||||
		if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
 | 
					 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
				
			||||||
			goto error2;
 | 
								goto error2;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (endp->trunk->cfg->osmux == OSMUX_USAGE_ONLY) {
 | 
							if (remote_osmux_cid >= 0) {
 | 
				
			||||||
 | 
								conn->osmux.remote_cid_present = true;
 | 
				
			||||||
 | 
								conn->osmux.remote_cid = remote_osmux_cid;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_ONLY) {
 | 
				
			||||||
		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: osmux only and no osmux offered\n");
 | 
								 "CRCX: osmux only and no osmux offered\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
				
			||||||
@@ -1020,7 +1026,7 @@ mgcp_header_done:
 | 
				
			|||||||
					  &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,
 | 
				
			||||||
				 "CRCX: inavlid local connection options!\n");
 | 
									 "CRCX: invalid local connection options!\n");
 | 
				
			||||||
			error_code = rc;
 | 
								error_code = rc;
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
 | 
				
			||||||
			goto error2;
 | 
								goto error2;
 | 
				
			||||||
@@ -1054,7 +1060,7 @@ mgcp_header_done:
 | 
				
			|||||||
	/* check connection mode setting */
 | 
						/* check connection mode setting */
 | 
				
			||||||
	if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
						if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
				
			||||||
	    && conn->conn->mode != MGCP_CONN_RECV_ONLY
 | 
						    && conn->conn->mode != MGCP_CONN_RECV_ONLY
 | 
				
			||||||
	    && conn->end.rtp_port == 0) {
 | 
						    && osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
 | 
				
			||||||
		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: selected connection mode type requires an opposite end!\n");
 | 
								 "CRCX: selected connection mode type requires an opposite end!\n");
 | 
				
			||||||
		error_code = 527;
 | 
							error_code = 527;
 | 
				
			||||||
@@ -1064,7 +1070,10 @@ mgcp_header_done:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Find a local address for conn based on policy and initial SDP remote
 | 
						/* Find a local address for conn based on policy and initial SDP remote
 | 
				
			||||||
	   information, then find a free port for it */
 | 
						   information, then find a free port for it */
 | 
				
			||||||
	mgcp_get_local_addr(conn->end.local_addr, conn);
 | 
						if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
 | 
				
			||||||
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
				
			||||||
 | 
							goto error2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (allocate_port(endp, conn) != 0) {
 | 
						if (allocate_port(endp, conn) != 0) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
@@ -1077,13 +1086,20 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Notify Osmux conn that CRCX was received */
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
 | 
							if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
 | 
				
			||||||
 | 
								goto error2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(trunk->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 &&
 | 
				
			||||||
	    mgcp_rtp_end_remote_addr_available(&conn->end) &&
 | 
					 | 
				
			||||||
	    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1118,7 +1134,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	const char *mode = NULL;
 | 
						const char *mode = NULL;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
        const char *conn_id = NULL;
 | 
					        const char *conn_id = NULL;
 | 
				
			||||||
	int osmux_cid = -2;
 | 
						int remote_osmux_cid = -2;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
				
			||||||
@@ -1174,9 +1190,9 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		case 'X':
 | 
							case 'X':
 | 
				
			||||||
			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
				/* If osmux is disabled, just skip setting it up */
 | 
									/* If osmux is disabled, just skip setting it up */
 | 
				
			||||||
				if (!endp->trunk->cfg->osmux)
 | 
									if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				osmux_cid = mgcp_osmux_setup(endp, line);
 | 
									remote_osmux_cid = mgcp_osmux_setup(endp, line);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/* Ignore unknown X-headers */
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
@@ -1253,30 +1269,39 @@ mgcp_header_done:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		OSMO_ASSERT(conn->osmux.cid_allocated);
 | 
							OSMO_ASSERT(conn->osmux.local_cid_allocated);
 | 
				
			||||||
		if (osmux_cid < -1) {
 | 
							if (remote_osmux_cid < -1) {
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "MDCX: Failed to parse Osmux CID!\n");
 | 
									 "MDCX: Failed to parse Osmux CID!\n");
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
		} else if (osmux_cid == -1) {
 | 
							} else if (remote_osmux_cid == -1) {
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "MDCX: wilcard in MDCX is not supported!\n");
 | 
									 "MDCX: wilcard in MDCX is not supported!\n");
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
		} else if (osmux_cid != (int) conn->osmux.cid) {
 | 
							} else if (conn->osmux.remote_cid_present &&
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
									remote_osmux_cid != conn->osmux.remote_cid) {
 | 
				
			||||||
				 "MDCX: changing already allocated CID is not supported!\n");
 | 
									LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			goto error3;
 | 
										"MDCX: changing already allocated CID is not supported!\n");
 | 
				
			||||||
 | 
									goto error3;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								conn->osmux.remote_cid_present = true;
 | 
				
			||||||
 | 
								conn->osmux.remote_cid = remote_osmux_cid;
 | 
				
			||||||
 | 
								if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
 | 
				
			||||||
 | 
									LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
										"MDCX: Osmux handling failed!\n");
 | 
				
			||||||
 | 
									goto error3;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* TODO: In the future (when we have recvCID!=sendCID), we need to
 | 
					 | 
				
			||||||
		   tell Osmux code that osmux_cid is to be used as sendCID for
 | 
					 | 
				
			||||||
		   that conn. */
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* MDCX may have provided a new remote address, which means we may need
 | 
						/* 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
 | 
						   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
 | 
						   happen for instance if MGW initially provided an IPv4 during CRCX
 | 
				
			||||||
	   ACK, and now MDCX tells us the remote has an IPv6 address. */
 | 
						   ACK, and now MDCX tells us the remote has an IPv6 address. */
 | 
				
			||||||
	mgcp_get_local_addr(new_local_addr, conn);
 | 
						if (mgcp_get_local_addr(new_local_addr, conn) < 0) {
 | 
				
			||||||
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
				
			||||||
 | 
							goto error3;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (strcmp(new_local_addr, conn->end.local_addr)) {
 | 
						if (strcmp(new_local_addr, conn->end.local_addr)) {
 | 
				
			||||||
		osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 | 
							osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 | 
				
			||||||
		mgcp_free_rtp_port(&conn->end);
 | 
							mgcp_free_rtp_port(&conn->end);
 | 
				
			||||||
@@ -1300,7 +1325,6 @@ mgcp_header_done:
 | 
				
			|||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(trunk->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 &&
 | 
				
			||||||
	    mgcp_rtp_end_remote_addr_available(&conn->end) &&
 | 
					 | 
				
			||||||
	    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1569,8 +1593,7 @@ static void mgcp_keepalive_timer_cb(void *_trunk)
 | 
				
			|||||||
		struct mgcp_endpoint *endp = trunk->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->type == MGCP_CONN_TYPE_RTP &&
 | 
								if (conn->type == MGCP_CONN_TYPE_RTP &&
 | 
				
			||||||
			    conn->mode == MGCP_CONN_RECV_ONLY &&
 | 
								    conn->mode == MGCP_CONN_RECV_ONLY)
 | 
				
			||||||
			     mgcp_rtp_end_remote_addr_available(&conn->u.rtp.end))
 | 
					 | 
				
			||||||
				send_dummy(endp, &conn->u.rtp);
 | 
									send_dummy(endp, &conn->u.rtp);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1624,7 +1647,6 @@ struct mgcp_config *mgcp_config_alloc(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cfg->source_port = 2427;
 | 
						cfg->source_port = 2427;
 | 
				
			||||||
	osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
 | 
						osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
 | 
				
			||||||
	osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
 | 
						cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
 | 
				
			||||||
	cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
 | 
						cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
				
			|||||||
	    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
						    { "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 = {
 | 
					static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mgcp",
 | 
						.group_name_prefix = "mgcp",
 | 
				
			||||||
	.group_description = "mgcp general statistics",
 | 
						.group_description = "mgcp general statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -71,7 +71,7 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
						[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "crcx",
 | 
						.group_name_prefix = "crcx",
 | 
				
			||||||
	.group_description = "crxc statistics",
 | 
						.group_description = "crxc statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -97,7 +97,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mdcx",
 | 
						.group_name_prefix = "mdcx",
 | 
				
			||||||
	.group_description = "mdcx statistics",
 | 
						.group_description = "mdcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -116,7 +116,7 @@ static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "dlcx",
 | 
						.group_name_prefix = "dlcx",
 | 
				
			||||||
	.group_description = "dlcx statistics",
 | 
						.group_description = "dlcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -130,7 +130,7 @@ static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
 | 
				
			|||||||
	[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
 | 
						[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 = {
 | 
					static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "e1",
 | 
						.group_name_prefix = "e1",
 | 
				
			||||||
	.group_description = "e1 statistics",
 | 
						.group_description = "e1 statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -138,7 +138,7 @@ const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = e1_rate_ctr_desc
 | 
						.ctr_desc = e1_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
					static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "all_rtp_conn",
 | 
						.group_name_prefix = "all_rtp_conn",
 | 
				
			||||||
	.group_description = "aggregated statistics for all rtp connections",
 | 
						.group_description = "aggregated statistics for all rtp connections",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -146,6 +146,14 @@ const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
						.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "all_osmux_conn",
 | 
				
			||||||
 | 
						.group_description = "aggregated statistics for all osmux connections",
 | 
				
			||||||
 | 
						.class_id = 1,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
 | 
				
			||||||
 | 
						.ctr_desc = all_osmux_conn_rate_ctr_desc
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate global rate counters
 | 
					/*! allocate global rate counters
 | 
				
			||||||
 *  (called once at startup).
 | 
					 *  (called once at startup).
 | 
				
			||||||
 *  \param[in] cfg mgw configuration for which the rate counters are allocated.
 | 
					 *  \param[in] cfg mgw configuration for which the rate counters are allocated.
 | 
				
			||||||
@@ -191,6 +199,7 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			|||||||
	static atomic_uint mdcx_rate_ctr_index = 0;
 | 
						static atomic_uint mdcx_rate_ctr_index = 0;
 | 
				
			||||||
	static atomic_uint dlcx_rate_ctr_index = 0;
 | 
						static atomic_uint dlcx_rate_ctr_index = 0;
 | 
				
			||||||
	static atomic_uint all_rtp_conn_rate_ctr_index = 0;
 | 
						static atomic_uint all_rtp_conn_rate_ctr_index = 0;
 | 
				
			||||||
 | 
						static atomic_uint all_osmux_conn_rate_ctr_index = 0;
 | 
				
			||||||
	char ctr_name[256];
 | 
						char ctr_name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
				
			||||||
@@ -229,6 +238,15 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			|||||||
			 trunk->trunk_nr);
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
		rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
 | 
							rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_osmux_conn_stats == NULL) {
 | 
				
			||||||
 | 
							ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
 | 
				
			||||||
 | 
													   all_osmux_conn_rate_ctr_index++);
 | 
				
			||||||
 | 
							if (!ratectr->all_osmux_conn_stats)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
				
			||||||
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
 | 
							rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* E1 specific */
 | 
						/* E1 specific */
 | 
				
			||||||
	if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
 | 
						if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
 | 
				
			||||||
@@ -265,6 +283,10 @@ void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
 | 
				
			|||||||
		rate_ctr_group_free(ratectr->all_rtp_conn_stats);
 | 
							rate_ctr_group_free(ratectr->all_rtp_conn_stats);
 | 
				
			||||||
		ratectr->all_rtp_conn_stats = NULL;
 | 
							ratectr->all_rtp_conn_stats = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_osmux_conn_stats) {
 | 
				
			||||||
 | 
							rate_ctr_group_free(ratectr->all_osmux_conn_stats);
 | 
				
			||||||
 | 
							ratectr->all_osmux_conn_stats = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* E1 specific */
 | 
						/* E1 specific */
 | 
				
			||||||
	if (ratectr->e1_stats) {
 | 
						if (ratectr->e1_stats) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -384,7 +384,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
		case 'm':
 | 
							case 'm':
 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
				
			||||||
			if (rc == 1) {
 | 
								if (rc == 1) {
 | 
				
			||||||
				rtp->rtp_port = htons(port);
 | 
									osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
 | 
				
			||||||
				rtp->rtcp_port = htons(port + 1);
 | 
									rtp->rtcp_port = htons(port + 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -432,7 +432,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	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), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
						     osmo_sockaddr_port(&rtp->addr.u.sa), 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");
 | 
				
			||||||
@@ -601,7 +601,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		payload_types[0] = payload_type;
 | 
							payload_types[0] = payload_type;
 | 
				
			||||||
		if (mgcp_conn_rtp_is_osmux(conn))
 | 
							if (mgcp_conn_rtp_is_osmux(conn))
 | 
				
			||||||
			local_port = endp->trunk->cfg->osmux_port;
 | 
								local_port = endp->trunk->cfg->osmux.local_port;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			local_port = conn->end.local_port;
 | 
								local_port = conn->end.local_port;
 | 
				
			||||||
		rc = add_audio(sdp, payload_types, 1, local_port);
 | 
							rc = add_audio(sdp, payload_types, 1, local_port);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ __attribute__((no_sanitize("undefined")))
 | 
				
			|||||||
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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
						struct mgcp_rtp_state *state = &conn->state;
 | 
				
			||||||
	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*expected = state->stats.cycles + state->stats.max_seq;
 | 
						*expected = state->stats.cycles + state->stats.max_seq;
 | 
				
			||||||
	*expected = *expected - state->stats.base_seq + 1;
 | 
						*expected = *expected - state->stats.base_seq + 1;
 | 
				
			||||||
@@ -80,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	int ploss;
 | 
						int ploss;
 | 
				
			||||||
	int nchars;
 | 
						int nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
						struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
						struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
						struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	calc_loss(conn, &expected, &ploss);
 | 
						calc_loss(conn, &expected, &ploss);
 | 
				
			||||||
	jitter = calc_jitter(&conn->state);
 | 
						jitter = calc_jitter(&conn->state);
 | 
				
			||||||
@@ -99,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	str += nchars;
 | 
						str += nchars;
 | 
				
			||||||
	str_len -= nchars;
 | 
						str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
 | 
						if (conn->conn->endp->trunk->cfg->osmux.usage != OSMUX_USAGE_OFF) {
 | 
				
			||||||
		/* Error Counter */
 | 
							/* Error Counter */
 | 
				
			||||||
		nchars = snprintf(str, str_len,
 | 
							nchars = snprintf(str, str_len,
 | 
				
			||||||
				  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
									  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
				
			||||||
@@ -112,9 +112,12 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
		str_len -= nchars;
 | 
							str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
							if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
				
			||||||
 | 
								struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
 | 
				
			||||||
 | 
								osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
				
			||||||
 | 
								osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
 | 
				
			||||||
			snprintf(str, str_len,
 | 
								snprintf(str, str_len,
 | 
				
			||||||
				 "\r\nX-Osmux-ST: CR=%u, BR=%u",
 | 
									 "\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
 | 
				
			||||||
				 conn->osmux.stats.chunks, conn->osmux.stats.octets);
 | 
									 osmux_chunks_rx->current, osmux_octets_rx->current);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
							vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (g_cfg->osmux) {
 | 
						switch (g_cfg->osmux.usage) {
 | 
				
			||||||
	case OSMUX_USAGE_ON:
 | 
						case OSMUX_USAGE_ON:
 | 
				
			||||||
		vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -141,17 +141,23 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (g_cfg->osmux) {
 | 
						if (g_cfg->osmux.usage != OSMUX_USAGE_OFF) {
 | 
				
			||||||
		vty_out(vty, " osmux bind-ip %s%s",
 | 
							if (g_cfg->osmux.local_addr_v4)
 | 
				
			||||||
			g_cfg->osmux_addr, VTY_NEWLINE);
 | 
								vty_out(vty, " osmux bind-ip %s%s",
 | 
				
			||||||
 | 
									g_cfg->osmux.local_addr_v4, VTY_NEWLINE);
 | 
				
			||||||
 | 
							if (g_cfg->osmux.local_addr_v6)
 | 
				
			||||||
 | 
								vty_out(vty, " osmux bind-ip-v6 %s%s",
 | 
				
			||||||
 | 
									g_cfg->osmux.local_addr_v6, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux batch-factor %d%s",
 | 
							vty_out(vty, " osmux batch-factor %d%s",
 | 
				
			||||||
			g_cfg->osmux_batch, VTY_NEWLINE);
 | 
								g_cfg->osmux.batch_factor, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux batch-size %u%s",
 | 
							vty_out(vty, " osmux batch-size %u%s",
 | 
				
			||||||
			g_cfg->osmux_batch_size, VTY_NEWLINE);
 | 
								g_cfg->osmux.batch_size, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux port %u%s",
 | 
							vty_out(vty, " osmux port %u%s",
 | 
				
			||||||
			g_cfg->osmux_port, VTY_NEWLINE);
 | 
								g_cfg->osmux.local_port, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux dummy %s%s",
 | 
							vty_out(vty, " osmux dummy %s%s",
 | 
				
			||||||
			g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
 | 
								g_cfg->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, " osmux peer-behind-nat %s%s",
 | 
				
			||||||
 | 
								g_cfg->osmux.peer_behind_nat ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->conn_timeout)
 | 
						if (g_cfg->conn_timeout)
 | 
				
			||||||
@@ -169,11 +175,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
						struct rate_ctr *rx_packets, *rx_bytes;
 | 
				
			||||||
	struct rate_ctr *dropped_packets;
 | 
						struct rate_ctr *dropped_packets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
						tx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	tx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
						tx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
	rx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
						rx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	rx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
						rx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	dropped_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_DROPPED_PACKETS_CTR);
 | 
						dropped_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_DROPPED_PACKETS_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty,
 | 
						vty_out(vty,
 | 
				
			||||||
		"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
							"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
@@ -189,7 +195,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
							rx_packets->current, rx_bytes->current, VTY_NEWLINE,
 | 
				
			||||||
		state->in_stream.err_ts_ctr->current,
 | 
							state->in_stream.err_ts_ctr->current,
 | 
				
			||||||
		state->out_stream.err_ts_ctr->current,
 | 
							state->out_stream.err_ts_ctr->current,
 | 
				
			||||||
	        VTY_NEWLINE,
 | 
							VTY_NEWLINE,
 | 
				
			||||||
		dropped_packets->current, VTY_NEWLINE,
 | 
							dropped_packets->current, VTY_NEWLINE,
 | 
				
			||||||
		codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
							codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
 | 
				
			||||||
		codec->frame_duration_num, codec->frame_duration_den,
 | 
							codec->frame_duration_num, codec->frame_duration_den,
 | 
				
			||||||
@@ -197,6 +203,30 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
							VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
				
			||||||
		codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
							codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
				
			||||||
		end->force_output_ptime, VTY_NEWLINE);
 | 
							end->force_output_ptime, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
 | 
							struct rate_ctr *rx_chunks, *rx_octets, *rtp_tx, *rtp_tx_dropped, *octets_tx;
 | 
				
			||||||
 | 
							rx_chunks = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
				
			||||||
 | 
							rx_octets = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_OCTETS_RX_CTR);
 | 
				
			||||||
 | 
							rtp_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_CTR);
 | 
				
			||||||
 | 
							rtp_tx_dropped =  rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
				
			||||||
 | 
							octets_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_AMR_OCTETS_TX_CTR);
 | 
				
			||||||
 | 
							vty_out(vty,
 | 
				
			||||||
 | 
							"   Osmux:%s"
 | 
				
			||||||
 | 
							"    State: %s%s"
 | 
				
			||||||
 | 
							"    Local CID: %d%s"
 | 
				
			||||||
 | 
							"    Remote CID: %d%s"
 | 
				
			||||||
 | 
							"    Chunks received: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
 | 
							"    RTP Packets encoded (Tx): %" PRIu64 " (%" PRIu64 " AMR octets total)%s"
 | 
				
			||||||
 | 
							"    AMR payloads Dropped (Tx): %" PRIu64 "%s",
 | 
				
			||||||
 | 
							VTY_NEWLINE, osmux_state_str(conn->osmux.state), VTY_NEWLINE,
 | 
				
			||||||
 | 
							conn->osmux.local_cid_allocated ? conn->osmux.local_cid : -1, VTY_NEWLINE,
 | 
				
			||||||
 | 
							conn->osmux.remote_cid_present ? conn->osmux.remote_cid : -1, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rx_chunks->current, rx_octets->current, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rtp_tx->current, octets_tx->current, VTY_NEWLINE,
 | 
				
			||||||
 | 
							rtp_tx_dropped->current, VTY_NEWLINE
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
					static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			||||||
@@ -289,6 +319,14 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
 | 
				
			|||||||
					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
										   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
				
			||||||
					   ratectr->all_rtp_conn_stats);
 | 
										   ratectr->all_rtp_conn_stats);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ratectr->all_osmux_conn_stats) {
 | 
				
			||||||
 | 
							vty_out(vty, "   %s:%s",
 | 
				
			||||||
 | 
								ratectr->all_osmux_conn_stats->desc->group_description,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out_rate_ctr_group_fmt(vty,
 | 
				
			||||||
 | 
										   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
				
			||||||
 | 
										   ratectr->all_osmux_conn_stats);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
						if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
				
			||||||
		vty_out(vty, "   %s:%s",
 | 
							vty_out(vty, "   %s:%s",
 | 
				
			||||||
@@ -342,7 +380,7 @@ static int mgcp_show(struct vty *vty, int argc, const char **argv,
 | 
				
			|||||||
	llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
						llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
				
			||||||
		dump_trunk(vty, trunk, show_stats, active_only);
 | 
							dump_trunk(vty, trunk, show_stats, active_only);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->osmux)
 | 
						if (g_cfg->osmux.usage != OSMUX_USAGE_OFF)
 | 
				
			||||||
		vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
							vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1539,12 +1577,12 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(argv[0], "off") == 0) {
 | 
						if (strcmp(argv[0], "off") == 0) {
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_OFF;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_OFF;
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	} else if (strcmp(argv[0], "on") == 0)
 | 
						} else if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_ON;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_ON;
 | 
				
			||||||
	else if (strcmp(argv[0], "only") == 0)
 | 
						else if (strcmp(argv[0], "only") == 0)
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_ONLY;
 | 
							g_cfg->osmux.usage = OSMUX_USAGE_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1552,12 +1590,29 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_ip,
 | 
					DEFUN(cfg_mgcp_osmux_ip,
 | 
				
			||||||
      cfg_mgcp_osmux_ip_cmd,
 | 
					      cfg_mgcp_osmux_ip_cmd,
 | 
				
			||||||
      "osmux bind-ip " VTY_IPV46_CMD,
 | 
					      "osmux bind-ip " VTY_IPV4_CMD,
 | 
				
			||||||
 | 
					      OSMUX_STR IP_STR
 | 
				
			||||||
 | 
					      "IPv4 Address to bind to\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v4, argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_ip_v6,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_ip_v6_cmd,
 | 
				
			||||||
 | 
					      "osmux bind-ip-v6 " VTY_IPV6_CMD,
 | 
				
			||||||
      OSMUX_STR IP_STR
 | 
					      OSMUX_STR IP_STR
 | 
				
			||||||
      "IPv4 Address to bind to\n"
 | 
					 | 
				
			||||||
      "IPv6 Address to bind to\n")
 | 
					      "IPv6 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
 | 
						osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v6, argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_port,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_port_cmd,
 | 
				
			||||||
 | 
					      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->osmux.local_port = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1566,7 +1621,7 @@ DEFUN(cfg_mgcp_osmux_batch_factor,
 | 
				
			|||||||
      "osmux batch-factor <1-8>",
 | 
					      "osmux batch-factor <1-8>",
 | 
				
			||||||
      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
					      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux_batch = atoi(argv[0]);
 | 
						g_cfg->osmux.batch_factor = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1575,15 +1630,7 @@ DEFUN(cfg_mgcp_osmux_batch_size,
 | 
				
			|||||||
      "osmux batch-size <1-65535>",
 | 
					      "osmux batch-size <1-65535>",
 | 
				
			||||||
      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
					      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux_batch_size = atoi(argv[0]);
 | 
						g_cfg->osmux.batch_size = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_port,
 | 
					 | 
				
			||||||
      cfg_mgcp_osmux_port_cmd,
 | 
					 | 
				
			||||||
      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	g_cfg->osmux_port = atoi(argv[0]);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1594,9 +1641,24 @@ DEFUN(cfg_mgcp_osmux_dummy,
 | 
				
			|||||||
      "Disable dummy padding\n")
 | 
					      "Disable dummy padding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(argv[0], "on") == 0)
 | 
						if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux_dummy = 1;
 | 
							g_cfg->osmux.dummy_padding = true;
 | 
				
			||||||
	else if (strcmp(argv[0], "off") == 0)
 | 
						else if (strcmp(argv[0], "off") == 0)
 | 
				
			||||||
		g_cfg->osmux_dummy = 0;
 | 
							g_cfg->osmux.dummy_padding = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_peer_behind_nat,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_peer_behind_nat_cmd,
 | 
				
			||||||
 | 
					      "osmux peer-behind-nat (on|off)",
 | 
				
			||||||
 | 
					      OSMUX_STR "Define whether peer is behind NAT\n"
 | 
				
			||||||
 | 
					      "Peer is behind NAT\n"
 | 
				
			||||||
 | 
					      "Peer is NOT behind NAT\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
 | 
							g_cfg->osmux.peer_behind_nat = true;
 | 
				
			||||||
 | 
						else if (strcmp(argv[0], "off") == 0)
 | 
				
			||||||
 | 
							g_cfg->osmux.peer_behind_nat = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1686,10 +1748,12 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
					 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_peer_behind_nat_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
				
			||||||
@@ -1734,9 +1798,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->osmux_port = OSMUX_PORT;
 | 
						cfg->osmux.local_port = OSMUX_DEFAULT_PORT;
 | 
				
			||||||
	cfg->osmux_batch = 4;
 | 
						cfg->osmux.batch_factor = 4;
 | 
				
			||||||
	cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
						cfg->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_cfg = cfg;
 | 
						g_cfg = cfg;
 | 
				
			||||||
	rc = vty_read_config_file(config_file, NULL);
 | 
						rc = vty_read_config_file(config_file, NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,6 @@
 | 
				
			|||||||
#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_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_ctrl.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
@@ -51,7 +50,7 @@
 | 
				
			|||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
#include <osmocom/ctrl/control_vty.h>
 | 
					#include <osmocom/ctrl/control_vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/telnet_interface.h>
 | 
					#include <osmocom/vty/telnet_interface.h>
 | 
				
			||||||
@@ -83,7 +82,7 @@ static int daemonize = 0;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const char *osmomgw_copyright =
 | 
					const char *osmomgw_copyright =
 | 
				
			||||||
	"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
 | 
						"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
 | 
				
			||||||
	"Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
 | 
						"Copyright (C) 2017-2022 by sysmocom s.f.m.c. GmbH\r\n"
 | 
				
			||||||
	"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
 | 
						"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
 | 
				
			||||||
	"Philipp Maier\r\n\r\n"
 | 
						"Philipp Maier\r\n\r\n"
 | 
				
			||||||
	"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
 | 
						"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
 | 
				
			||||||
@@ -95,7 +94,7 @@ static char *config_file = "osmo-mgw.cfg";
 | 
				
			|||||||
/* used by msgb and mgcp */
 | 
					/* used by msgb and mgcp */
 | 
				
			||||||
void *tall_mgw_ctx = NULL;
 | 
					void *tall_mgw_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_help()
 | 
					static void print_help(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	printf("Some useful options:\n");
 | 
						printf("Some useful options:\n");
 | 
				
			||||||
	printf(" -h --help is printing this text.\n");
 | 
						printf(" -h --help is printing this text.\n");
 | 
				
			||||||
@@ -295,13 +294,22 @@ static const struct log_info_cat log_categories[] = {
 | 
				
			|||||||
		  .name = "DRTP",
 | 
							  .name = "DRTP",
 | 
				
			||||||
		  .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] = {
 | 
						[DE1] = {
 | 
				
			||||||
		  .name = "DE1",
 | 
							  .name = "DE1",
 | 
				
			||||||
		  .description = "E1 line handling",
 | 
							  .description = "E1 line handling",
 | 
				
			||||||
		  .color = "\033[1;31m",
 | 
							  .color = "\033[1;31m",
 | 
				
			||||||
		  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
							  .enabled = 1,
 | 
				
			||||||
 | 
							  .loglevel = LOGL_NOTICE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[DOSMUX] = {
 | 
				
			||||||
 | 
							  .name = "DOSMUX",
 | 
				
			||||||
 | 
							  .description = "Osmux (Osmocom RTP multiplexing)",
 | 
				
			||||||
 | 
							  .color = "\033[1;32m",
 | 
				
			||||||
 | 
							  .enabled = 1,
 | 
				
			||||||
 | 
							  .loglevel = LOGL_NOTICE,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -357,7 +365,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
						cfg->ctrl = ctrl_interface_setup(cfg, OSMO_CTRL_PORT_MGW, NULL);
 | 
				
			||||||
	if (!cfg->ctrl) {
 | 
						if (!cfg->ctrl) {
 | 
				
			||||||
		fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
							fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
				
			||||||
			ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
								ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -838,7 +838,7 @@ static void test_messages(void)
 | 
				
			|||||||
				if (endp->local_options.pkt_period_min ||
 | 
									if (endp->local_options.pkt_period_min ||
 | 
				
			||||||
				    endp->local_options.pkt_period_max)
 | 
									    endp->local_options.pkt_period_max)
 | 
				
			||||||
					printf
 | 
										printf
 | 
				
			||||||
					    ("Requested packetetization period: "
 | 
										    ("Requested packetization period: "
 | 
				
			||||||
					     "%d-%d\n",
 | 
										     "%d-%d\n",
 | 
				
			||||||
					     endp->local_options.pkt_period_min,
 | 
										     endp->local_options.pkt_period_min,
 | 
				
			||||||
					     endp->
 | 
										     endp->
 | 
				
			||||||
@@ -1071,7 +1071,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
				    "test-connection");
 | 
									    "test-connection");
 | 
				
			||||||
		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
							conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
				
			||||||
		state = &conn->state;
 | 
							state = &conn->state;
 | 
				
			||||||
		packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
							packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->stats.initialized = 1;
 | 
							state->stats.initialized = 1;
 | 
				
			||||||
		state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
							state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
				
			||||||
@@ -1492,7 +1492,7 @@ 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);
 | 
				
			||||||
	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(osmo_sockaddr_port(&conn->end.addr.u.sa) == 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.u.sa.sa_family == AF_INET);
 | 
						OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
 | 
				
			||||||
@@ -1632,7 +1632,8 @@ static void test_osmux_cid(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 256; ++i) {
 | 
						for (i = 0; i < 256; ++i) {
 | 
				
			||||||
		id = osmux_cid_pool_get_next();
 | 
							id = osmux_cid_pool_get_next();
 | 
				
			||||||
		OSMO_ASSERT(id == i);
 | 
							/* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
 | 
				
			||||||
 | 
							OSMO_ASSERT(id == ((i + 1) & 0xff));
 | 
				
			||||||
		OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
 | 
							OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2078,7 +2079,7 @@ static void test_mgcp_codec_pt_translate(void)
 | 
				
			|||||||
	OSMO_ASSERT(ok);
 | 
						OSMO_ASSERT(ok);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_conn_id_matching()
 | 
					void test_conn_id_matching(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint endp = {};
 | 
						struct mgcp_endpoint endp = {};
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
@@ -2118,7 +2119,7 @@ void test_conn_id_matching()
 | 
				
			|||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_e1_trunk_nr_from_epname()
 | 
					void test_e1_trunk_nr_from_epname(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -2168,7 +2169,7 @@ void test_e1_trunk_nr_from_epname()
 | 
				
			|||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_mgcp_is_rtp_dummy_payload()
 | 
					void test_mgcp_is_rtp_dummy_payload(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* realistic rtp packet */
 | 
						/* realistic rtp packet */
 | 
				
			||||||
	static const char rtp_payload[] =
 | 
						static const char rtp_payload[] =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -315,7 +315,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_mgcp_client_cancel()
 | 
					void test_mgcp_client_cancel(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
@@ -487,7 +487,7 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_sdp_section_start()
 | 
					void test_sdp_section_start(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	int failures = 0;
 | 
						int failures = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user