mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			100 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					306dc09d37 | ||
| 
						 | 
					eb282efa67 | ||
| 
						 | 
					02d5c8798b | ||
| 
						 | 
					efe3f98ec7 | ||
| 
						 | 
					3ebf7e2f05 | ||
| 
						 | 
					33826246c5 | ||
| 
						 | 
					9ef0c11abd | ||
| 
						 | 
					109ff5244e | ||
| 
						 | 
					4cf5e71a4b | ||
| 
						 | 
					8c6f3141e2 | ||
| 
						 | 
					12220eea9c | ||
| 
						 | 
					536dff1bb8 | ||
| 
						 | 
					ee784f9844 | ||
| 
						 | 
					740af6ed44 | ||
| 
						 | 
					782d607962 | ||
| 
						 | 
					50e52e45f9 | ||
| 
						 | 
					a2d10216ea | ||
| 
						 | 
					f54eb96338 | ||
| 
						 | 
					a2b1c5e6f6 | ||
| 
						 | 
					c5c1430a1c | ||
| 
						 | 
					f7de9aea7b | ||
| 
						 | 
					199c5e965e | ||
| 
						 | 
					06a49fc04b | ||
| 
						 | 
					6349bd422a | ||
| 
						 | 
					796a4a1325 | ||
| 
						 | 
					2cf6652ba2 | ||
| 
						 | 
					9b508f6b53 | ||
| 
						 | 
					6e26c70f46 | ||
| 
						 | 
					9a34592c09 | ||
| 
						 | 
					7eb6f2cb56 | ||
| 
						 | 
					83fd8a5692 | ||
| 
						 | 
					17058484d1 | ||
| 
						 | 
					166077ea48 | ||
| 
						 | 
					0c6c3c1da6 | ||
| 
						 | 
					fe9a1fe03b | ||
| 
						 | 
					1e4a34d45e | ||
| 
						 | 
					189f29e939 | ||
| 
						 | 
					d2ce444008 | ||
| 
						 | 
					ef9420adf5 | ||
| 
						 | 
					cb96e05a91 | ||
| 
						 | 
					f6387dc766 | ||
| 
						 | 
					1b1d7ed98f | ||
| 
						 | 
					df7d97e4b4 | ||
| 
						 | 
					85978dadab | ||
| 
						 | 
					9aaaab6b3b | ||
| 
						 | 
					c1ad553d86 | ||
| 
						 | 
					c1bf4694e7 | ||
| 
						 | 
					1442c5a99e | ||
| 
						 | 
					dac2ca7e21 | ||
| 
						 | 
					375252279c | ||
| 
						 | 
					295570c631 | ||
| 
						 | 
					a93c6e9263 | ||
| 
						 | 
					30907dc9d8 | ||
| 
						 | 
					14f8a08f44 | ||
| 
						 | 
					c63f15a9a7 | ||
| 
						 | 
					ca538fc5eb | ||
| 
						 | 
					6be2c49538 | ||
| 
						 | 
					91088c305f | ||
| 
						 | 
					900cd6518a | ||
| 
						 | 
					fa810e8ccd | ||
| 
						 | 
					497611ae84 | ||
| 
						 | 
					2b89617aad | ||
| 
						 | 
					b542b0457b | ||
| 
						 | 
					120568651a | ||
| 
						 | 
					f1d301a9a6 | ||
| 
						 | 
					c9a6280c94 | ||
| 
						 | 
					b5583cde41 | ||
| 
						 | 
					6c1cd63a57 | ||
| 
						 | 
					0d7ba56f5c | ||
| 
						 | 
					3ac604e3ad | ||
| 
						 | 
					9fb8ddf00e | ||
| 
						 | 
					182ca3bad4 | ||
| 
						 | 
					f027f17dcb | ||
| 
						 | 
					ac772d8b0c | ||
| 
						 | 
					9d9f44ac71 | ||
| 
						 | 
					84274e4e9b | ||
| 
						 | 
					c5479fe086 | ||
| 
						 | 
					538d2c53d9 | ||
| 
						 | 
					8de58e79b8 | ||
| 
						 | 
					5e8d7995d1 | ||
| 
						 | 
					3239f6212e | ||
| 
						 | 
					209eb9f103 | ||
| 
						 | 
					ef6304e4a1 | ||
| 
						 | 
					21cdbfc196 | ||
| 
						 | 
					fc8067348b | ||
| 
						 | 
					9f11dc5616 | ||
| 
						 | 
					ca0818c760 | ||
| 
						 | 
					c12bfb7ffc | ||
| 
						 | 
					228e591589 | ||
| 
						 | 
					58128258b0 | ||
| 
						 | 
					e7ae69a7be | ||
| 
						 | 
					7e37ce6008 | ||
| 
						 | 
					dbe09dd515 | ||
| 
						 | 
					217d31d62f | ||
| 
						 | 
					47642f245d | ||
| 
						 | 
					cb760bdebe | ||
| 
						 | 
					e3f8bca424 | ||
| 
						 | 
					9fc8a02196 | ||
| 
						 | 
					e36b775eae | ||
| 
						 | 
					622dd61764 | 
							
								
								
									
										37
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,20 +2,13 @@ debian/*.log
 | 
				
			|||||||
*.o
 | 
					*.o
 | 
				
			||||||
*.lo
 | 
					*.lo
 | 
				
			||||||
*.a
 | 
					*.a
 | 
				
			||||||
 | 
					*.la
 | 
				
			||||||
.deps
 | 
					.deps
 | 
				
			||||||
Makefile
 | 
					Makefile
 | 
				
			||||||
Makefile.in
 | 
					Makefile.in
 | 
				
			||||||
bscconfig.h
 | 
					bscconfig.h
 | 
				
			||||||
bscconfig.h.in
 | 
					bscconfig.h.in
 | 
				
			||||||
openbsc.pc
 | 
					src/osmo-mgw/osmo-mgw
 | 
				
			||||||
src/osmo-nitb/osmo-nitb
 | 
					 | 
				
			||||||
src/osmo-bsc_mgcp/osmo-bsc_mgcp
 | 
					 | 
				
			||||||
src/osmo-bsc/osmo-bsc
 | 
					 | 
				
			||||||
src/utils/meas_vis
 | 
					 | 
				
			||||||
src/utils/meas_json
 | 
					 | 
				
			||||||
src/utils/osmo-meas-pcap2db
 | 
					 | 
				
			||||||
src/utils/osmo-meas-udp2db
 | 
					 | 
				
			||||||
src/utils/smpp_mirror
 | 
					 | 
				
			||||||
*.*~
 | 
					*.*~
 | 
				
			||||||
*.sw?
 | 
					*.sw?
 | 
				
			||||||
.libs
 | 
					.libs
 | 
				
			||||||
@@ -46,32 +39,9 @@ m4/*.m4
 | 
				
			|||||||
.version
 | 
					.version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# apps and app data
 | 
					 | 
				
			||||||
hlr.sqlite3
 | 
					 | 
				
			||||||
src/utils/bs11_config
 | 
					 | 
				
			||||||
src/ipaccess/ipaccess-config
 | 
					 | 
				
			||||||
src/ipaccess/abisip-find
 | 
					 | 
				
			||||||
src/ipaccess/ipaccess-firmware
 | 
					 | 
				
			||||||
src/ipaccess/ipaccess-proxy
 | 
					 | 
				
			||||||
src/utils/isdnsync
 | 
					 | 
				
			||||||
src/nat/bsc_nat
 | 
					 | 
				
			||||||
src/gprs/osmo-sgsn
 | 
					 | 
				
			||||||
src/gprs/osmo-gbproxy
 | 
					 | 
				
			||||||
src/gprs/osmo-gtphub
 | 
					 | 
				
			||||||
src/osmo-bsc_nat/osmo-bsc_nat
 | 
					 | 
				
			||||||
src/libcommon/gsup_test_client
 | 
					 | 
				
			||||||
src/osmo-msc/osmo-msc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#tests
 | 
					#tests
 | 
				
			||||||
tests/testsuite.dir
 | 
					tests/testsuite.dir
 | 
				
			||||||
tests/*/*_test
 | 
					tests/*/*_test
 | 
				
			||||||
# ignore compiled binaries like msc_vlr_test_foo; do not ignore
 | 
					 | 
				
			||||||
# msc_vlr_test_foo.{c,ok,err}, but do still ignore the corresponding .o object
 | 
					 | 
				
			||||||
# files:
 | 
					 | 
				
			||||||
tests/msc_vlr/msc_vlr_test_*
 | 
					 | 
				
			||||||
!tests/msc_vlr/msc_vlr_test_*.*
 | 
					 | 
				
			||||||
tests/msc_vlr/msc_vlr_test_*.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
tests/atconfig
 | 
					tests/atconfig
 | 
				
			||||||
tests/atlocal
 | 
					tests/atlocal
 | 
				
			||||||
@@ -79,10 +49,7 @@ tests/package.m4
 | 
				
			|||||||
tests/testsuite
 | 
					tests/testsuite
 | 
				
			||||||
tests/testsuite.log
 | 
					tests/testsuite.log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gsn_restart
 | 
					 | 
				
			||||||
src/openbsc.cfg*
 | 
					 | 
				
			||||||
writtenconfig/
 | 
					writtenconfig/
 | 
				
			||||||
gtphub_restart_count
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# manuals
 | 
					# manuals
 | 
				
			||||||
doc/manuals/*.html
 | 
					doc/manuals/*.html
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							@@ -42,7 +42,7 @@ AC_SUBST(LIBRARY_DL)
 | 
				
			|||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.0.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.0.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.0.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.0.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.4.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.6.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AC_ARG_ENABLE(sanitize,
 | 
					AC_ARG_ENABLE(sanitize,
 | 
				
			||||||
	[AS_HELP_STRING(
 | 
						[AS_HELP_STRING(
 | 
				
			||||||
@@ -76,21 +76,10 @@ fi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
dnl Checks for typedefs, structures and compiler characteristics
 | 
					dnl Checks for typedefs, structures and compiler characteristics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The following test is taken from WebKit's webkit.m4
 | 
					 | 
				
			||||||
saved_CFLAGS="$CFLAGS"
 | 
					 | 
				
			||||||
CFLAGS="$CFLAGS -fvisibility=hidden "
 | 
					 | 
				
			||||||
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
 | 
					 | 
				
			||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
 | 
					 | 
				
			||||||
      [ AC_MSG_RESULT([yes])
 | 
					 | 
				
			||||||
        SYMBOL_VISIBILITY="-fvisibility=hidden"],
 | 
					 | 
				
			||||||
        AC_MSG_RESULT([no]))
 | 
					 | 
				
			||||||
CFLAGS="$saved_CFLAGS"
 | 
					 | 
				
			||||||
AC_SUBST(SYMBOL_VISIBILITY)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
 | 
					AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
 | 
					AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
 | 
					AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=null-dereference], [CFLAGS="$CFLAGS -Werror=null-dereference"])
 | 
					AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
 | 
					AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
 | 
				
			||||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
 | 
					AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,6 +195,7 @@ AC_OUTPUT(
 | 
				
			|||||||
    tests/atlocal
 | 
					    tests/atlocal
 | 
				
			||||||
    tests/mgcp_client/Makefile
 | 
					    tests/mgcp_client/Makefile
 | 
				
			||||||
    tests/mgcp/Makefile
 | 
					    tests/mgcp/Makefile
 | 
				
			||||||
 | 
					    tests/iuup/Makefile
 | 
				
			||||||
    doc/Makefile
 | 
					    doc/Makefile
 | 
				
			||||||
    doc/examples/Makefile
 | 
					    doc/examples/Makefile
 | 
				
			||||||
    doc/manuals/Makefile
 | 
					    doc/manuals/Makefile
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,4 +63,5 @@ if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
 | 
				
			|||||||
	make -C "$base/doc/manuals" publish
 | 
						make -C "$base/doc/manuals" publish
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$MAKE maintainer-clean
 | 
				
			||||||
osmo-clean-workspace.sh
 | 
					osmo-clean-workspace.sh
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										106
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,109 @@
 | 
				
			|||||||
 | 
					osmo-mgw (1.6.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Oliver Smith ]
 | 
				
			||||||
 | 
					  * Cosmetic: fix spaces/tabs in mgcp_requests[]
 | 
				
			||||||
 | 
					  * Inactive connection cleanup (disabled by default)
 | 
				
			||||||
 | 
					  * debian: create -doc subpackage with pdf manuals
 | 
				
			||||||
 | 
					  * vty: allow 0 as conn-timeout to disable it
 | 
				
			||||||
 | 
					  * vty: update desc of conn-timeout
 | 
				
			||||||
 | 
					  * manuals: update VTY documentation
 | 
				
			||||||
 | 
					  * "make dist" fix for: no rule to make mgcp_common.h
 | 
				
			||||||
 | 
					  * contrib/jenkins.sh: run "make maintainer-clean"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Philipp Maier ]
 | 
				
			||||||
 | 
					  * Add option to GSM HR frames to RFC5593 representation
 | 
				
			||||||
 | 
					  * mgcp_sdp: cosmetic: correct typo in comment
 | 
				
			||||||
 | 
					  * mgco_client: cosmetic: remove excess whitespace
 | 
				
			||||||
 | 
					  * mgcp_sdp: mgcp_sdp.c does not include own header file
 | 
				
			||||||
 | 
					  * mgcp_sdp: untangle parsing of a= parameters
 | 
				
			||||||
 | 
					  * mgcp_network: use mgcp_rtp_codec in downlink format callback
 | 
				
			||||||
 | 
					  * AMR: Add function to convert between bw-effient and octet aligned mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Neels Hofmeyr ]
 | 
				
			||||||
 | 
					  * log: don't spam with "can not patch PT" messages
 | 
				
			||||||
 | 
					  * mgcp client: allow setting conn mode for CRCX and MDCX
 | 
				
			||||||
 | 
					  * make codec_table public as osmo_mgcpc_codec_names
 | 
				
			||||||
 | 
					  * move MGW endpoint FSM from osmo-bsc to here
 | 
				
			||||||
 | 
					  * fix: multiple initial CRCX
 | 
				
			||||||
 | 
					  * constify map_codec_to_pt() ptmap arg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 | 
					  * mgcp-client: whitespace cleanup in mgcp_client.c
 | 
				
			||||||
 | 
					  * mgcp-client: Sanitize implementation of mgcp_client_rtpbridge_wildcard
 | 
				
			||||||
 | 
					  * libosmo-mgcp: Use trunk type during endpoint allocation
 | 
				
			||||||
 | 
					  * cosmetic: Fix typos in comment
 | 
				
			||||||
 | 
					  * cosmetic: tests: mgcp_client_test: clean trailing whitespace
 | 
				
			||||||
 | 
					  * mgcp_msg: Log faulty line on Osmux parsing error
 | 
				
			||||||
 | 
					  * cosmetic: handle_modify_con: Fix indentation level
 | 
				
			||||||
 | 
					  * Introduce log fmt helpers LOGPENDP and LOGPCONN
 | 
				
			||||||
 | 
					  * create_response_with_sdp: Fix inclusion of X-Osmux
 | 
				
			||||||
 | 
					  * osmux: Cleanup of CID alloc pool APIs
 | 
				
			||||||
 | 
					  * mgcp_osmux.c: osmux_enable_endpoint: Fix incorrect return check
 | 
				
			||||||
 | 
					  * osmux: Log osmux socket during osmux_init
 | 
				
			||||||
 | 
					  * mgcp-cli: Change osmo_mgcpc_ep_fsm name to avoid collision with old osmo-bsc
 | 
				
			||||||
 | 
					  * osmux: Document func and return different rc upon osmux init failure
 | 
				
			||||||
 | 
					  * osmux: Fix reception of legacy dummy payloads
 | 
				
			||||||
 | 
					  * osmux: Use LOGPCONN in several log calls
 | 
				
			||||||
 | 
					  * cosmetic: mgcp_udp_send: Document port param is in network byte order
 | 
				
			||||||
 | 
					  * cosmetic: osmux: Document network byte order in port variable
 | 
				
			||||||
 | 
					  * vty: Allow enabling Osmux
 | 
				
			||||||
 | 
					  * osmux: Allocate CID during CRCX
 | 
				
			||||||
 | 
					  * osmux: Introduce mgcp_conn_rtp_is_osmux() helper
 | 
				
			||||||
 | 
					  * osmux: Mark conn_rtp->type as osmux during CRCX
 | 
				
			||||||
 | 
					  * mgcp-cli: Allow submitting X-Osmux on CRCX request
 | 
				
			||||||
 | 
					  * mgcp-cli: Parse X-Osmux on CRCX response
 | 
				
			||||||
 | 
					  * osmux: Handle Osmux MGCP extension in MDCX messages
 | 
				
			||||||
 | 
					  * mgcp-cli: Allow submitting X-Osmux on MDCX request
 | 
				
			||||||
 | 
					  * mgcp-cli: Parse X-Osmux on MDCX response
 | 
				
			||||||
 | 
					  * osmux: Drop unneeded OSMUX_STATE_NEGOTIATING
 | 
				
			||||||
 | 
					  * mgcp-cli: endpoint_fsm: Add API to retrieve Osmux CID from MGW
 | 
				
			||||||
 | 
					  * osmux: Provide correct local port during mgcp resp
 | 
				
			||||||
 | 
					  * osmux: Use remote port to send osmux frames
 | 
				
			||||||
 | 
					  * osmux: Improve logging around osmux enabling events
 | 
				
			||||||
 | 
					  * osmux: Delay osmux enable of conn until remote addr is configured by MDCX
 | 
				
			||||||
 | 
					  * osmux: Redo read/write osmux glue code to have data routed correctly
 | 
				
			||||||
 | 
					  * mgw, mgcp-li: Handle X-Osmux param name as case insensitive
 | 
				
			||||||
 | 
					  * osmux: Use DUMMY ft msg as per Osmux spec
 | 
				
			||||||
 | 
					  * osmux: Fix loopback for Osmux connections
 | 
				
			||||||
 | 
					  * osmux: Fix CID release for non-enabled connections
 | 
				
			||||||
 | 
					  * osmux: Fix hardcoded rtp payload_type 98 in osmux conn
 | 
				
			||||||
 | 
					  * mgcp-cli: Validate osmux cid value during mgcp_msg_gen
 | 
				
			||||||
 | 
					  * mgw: Support uppercase LCO options
 | 
				
			||||||
 | 
					  * mgw: Support lowercase header parameters
 | 
				
			||||||
 | 
					  * mgcp-cli: Support lowercase header parameters
 | 
				
			||||||
 | 
					  * mgw: Support receiving uppercase connection mode
 | 
				
			||||||
 | 
					  * mgw: Support receiving lowercase LCO codec
 | 
				
			||||||
 | 
					  * mgw: Make check of duplicated LCO fields case insensitive
 | 
				
			||||||
 | 
					  * mgw: Allow receiving lowercase MGCP header keyword
 | 
				
			||||||
 | 
					  * mgw: Allow receiving lowercase X-Osmo-Ign Callid field
 | 
				
			||||||
 | 
					  * mgw: Allow receiving uppercase noanswer keyword
 | 
				
			||||||
 | 
					  * doc: X-Osmo-IGN: small formatting and typo fixes
 | 
				
			||||||
 | 
					  * doc: Add Osmux documentation to OsmoMGW User Manual
 | 
				
			||||||
 | 
					  * Catch unsigned integer MGCP parsing errors with strtoul
 | 
				
			||||||
 | 
					  * Fix return variable of strtoul()
 | 
				
			||||||
 | 
					  * Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
 | 
				
			||||||
 | 
					  * configure.ac: Require libosmo-netif 0.6.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Alexander Couzens ]
 | 
				
			||||||
 | 
					  * mgcp_internal: LOGPENDP: ensure *endp is not NULL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Harald Welte ]
 | 
				
			||||||
 | 
					  * handle NULL return of rate_ctr_group_alloc()
 | 
				
			||||||
 | 
					  * update .gitignore
 | 
				
			||||||
 | 
					  * mgcp_sdp: Don't check if an unsigned int is below 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Vadim Yanitskiy ]
 | 
				
			||||||
 | 
					  * configure.ac: drop useless check for -fvisibility=hidden
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Daniel Willmann ]
 | 
				
			||||||
 | 
					  * manuals: Add script to regenerate vty/counter documentation
 | 
				
			||||||
 | 
					  * manuals: Update vty/counter documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [ Hoernchen ]
 | 
				
			||||||
 | 
					  * turn -Werror=null-dereference into a warning
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Pau Espin Pedrol <pespin@sysmocom.de>  Wed, 07 Aug 2019 16:52:58 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
osmo-mgw (1.5.0) unstable; urgency=medium
 | 
					osmo-mgw (1.5.0) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					  [ Pau Espin Pedrol ]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -7,7 +7,8 @@ Build-Depends: debhelper (>=9),
 | 
				
			|||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev,
 | 
					               libosmocore-dev,
 | 
				
			||||||
               libosmo-netif-dev
 | 
					               libosmo-netif-dev,
 | 
				
			||||||
 | 
					               osmo-gsm-manuals-dev
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
					Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
				
			||||||
Vcs-Browser: https://git.osmocom.org/osmo-mgw/
 | 
					Vcs-Browser: https://git.osmocom.org/osmo-mgw/
 | 
				
			||||||
@@ -19,7 +20,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-client5
 | 
					Package: libosmo-mgcp-client6
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
@@ -31,5 +32,14 @@ Package: libosmo-mgcp-client-dev
 | 
				
			|||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Depends: libosmo-mgcp-client5 (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: libosmo-mgcp-client6 (= ${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
 | 
				
			||||||
 | 
					Architecture: all
 | 
				
			||||||
 | 
					Section: doc
 | 
				
			||||||
 | 
					Priority: optional
 | 
				
			||||||
 | 
					Depends: ${misc:Depends}
 | 
				
			||||||
 | 
					Description: ${misc:Package} PDF documentation
 | 
				
			||||||
 | 
					 Various manuals: user manual, VTY reference manual and/or
 | 
				
			||||||
 | 
					 protocol/interface manuals.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								debian/osmo-mgw-doc.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-mgw-doc.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					usr/share/doc/osmo-mgw-doc/*.pdf
 | 
				
			||||||
							
								
								
									
										6
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -30,6 +30,10 @@ override_dh_auto_test:
 | 
				
			|||||||
	dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
 | 
						dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_auto_configure:
 | 
					override_dh_auto_configure:
 | 
				
			||||||
	dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
 | 
						dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
 | 
				
			||||||
 | 
					override_dh_compress:
 | 
				
			||||||
 | 
						dh_compress -X.pdf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
 | 
					# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
EXTRA_DIST = osmomgw-usermanual.adoc \
 | 
					EXTRA_DIST = osmomgw-usermanual.adoc \
 | 
				
			||||||
    osmomgw-usermanual-docinfo.xml \
 | 
					    osmomgw-usermanual-docinfo.xml \
 | 
				
			||||||
    osmomgw-vty-reference.xml \
 | 
					    osmomgw-vty-reference.xml \
 | 
				
			||||||
 | 
					    regen_doc.sh \
 | 
				
			||||||
    chapters \
 | 
					    chapters \
 | 
				
			||||||
    vty
 | 
					    vty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,5 +13,6 @@ if BUILD_MANUALS
 | 
				
			|||||||
  VTY_REFERENCE = osmomgw-vty-reference.xml
 | 
					  VTY_REFERENCE = osmomgw-vty-reference.xml
 | 
				
			||||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OSMO_REPOSITORY = osmo-mgw
 | 
				
			||||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
 | 
					  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,79 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// autogenerated by show asciidoc counters
 | 
					// autogenerated by show asciidoc counters
 | 
				
			||||||
These counters and their description based on OsmoMGW 1.3.0.34-9cd52 (OsmoMGW).
 | 
					These counters and their description based on OsmoMGW 1.5.0.64-189f (OsmoMGW).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
=== Rate Counters
 | 
					=== Rate Counters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// generating tables for rate_ctr_group
 | 
					// generating tables for rate_ctr_group
 | 
				
			||||||
 | 
					// rate_ctr_group table aggregated statistics for all rtp connections
 | 
				
			||||||
 | 
					.all_rtp_conn - aggregated statistics for all rtp connections
 | 
				
			||||||
 | 
					[options="header"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					| Name | Reference | Description
 | 
				
			||||||
 | 
					| all_rtp:err_tstmp_in | <<all_rtp_conn_all_rtp:err_tstmp_in>> | Total inbound rtp-stream timestamp errors.
 | 
				
			||||||
 | 
					| all_rtp:err_tstmp_out | <<all_rtp_conn_all_rtp:err_tstmp_out>> | Total outbound rtp-stream timestamp errors.
 | 
				
			||||||
 | 
					| all_rtp:packets_rx | <<all_rtp_conn_all_rtp:packets_rx>> | Total inbound rtp packets.
 | 
				
			||||||
 | 
					| all_rtp:octets_rx | <<all_rtp_conn_all_rtp:octets_rx>> | Total inbound rtp octets.
 | 
				
			||||||
 | 
					| all_rtp:packets_tx | <<all_rtp_conn_all_rtp:packets_tx>> | Total outbound rtp packets.
 | 
				
			||||||
 | 
					| all_rtp:octets_tx | <<all_rtp_conn_all_rtp:octets_tx>> | Total outbound rtp octets.
 | 
				
			||||||
 | 
					| all_rtp:dropped | <<all_rtp_conn_all_rtp:dropped>> | Total dropped rtp packets.
 | 
				
			||||||
 | 
					| all_rtp:num_closed_conns | <<all_rtp_conn_all_rtp:num_closed_conns>> | Total number of rtp connections closed.
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					// rate_ctr_group table dlcx statistics
 | 
				
			||||||
 | 
					.dlcx - dlcx statistics
 | 
				
			||||||
 | 
					[options="header"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					| Name | Reference | Description
 | 
				
			||||||
 | 
					| dlcx:success | <<dlcx_dlcx:success>> | DLCX command processed successfully.
 | 
				
			||||||
 | 
					| dlcx:wildcard | <<dlcx_dlcx:wildcard>> | wildcard names in DLCX commands are unsupported.
 | 
				
			||||||
 | 
					| dlcx:no_conn | <<dlcx_dlcx:no_conn>> | endpoint specified in DLCX command has no active connections.
 | 
				
			||||||
 | 
					| dlcx:callid | <<dlcx_dlcx:callid>> | CallId specified in DLCX command mismatches endpoint's CallId .
 | 
				
			||||||
 | 
					| dlcx:connid | <<dlcx_dlcx:connid>> | connection ID specified in DLCX command does not exist on endpoint.
 | 
				
			||||||
 | 
					| dlcx:unhandled_param | <<dlcx_dlcx:unhandled_param>> | unhandled parameter in DLCX command.
 | 
				
			||||||
 | 
					| dlcx:rejected | <<dlcx_dlcx:rejected>> | connection deletion rejected by policy.
 | 
				
			||||||
 | 
					| dlcx:deferred | <<dlcx_dlcx:deferred>> | connection deletion deferred by policy.
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					// rate_ctr_group table mdcx statistics
 | 
				
			||||||
 | 
					.mdcx - mdcx statistics
 | 
				
			||||||
 | 
					[options="header"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					| Name | Reference | Description
 | 
				
			||||||
 | 
					| mdcx:success | <<mdcx_mdcx:success>> | MDCX command processed successfully.
 | 
				
			||||||
 | 
					| mdcx:wildcard | <<mdcx_mdcx:wildcard>> | wildcard endpoint names in MDCX commands are unsupported.
 | 
				
			||||||
 | 
					| mdcx:no_conn | <<mdcx_mdcx:no_conn>> | endpoint specified in MDCX command has no active connections.
 | 
				
			||||||
 | 
					| mdcx:callid | <<mdcx_mdcx:callid>> | invalid CallId specified in MDCX command.
 | 
				
			||||||
 | 
					| mdcx:connid | <<mdcx_mdcx:connid>> | invalid connection ID specified in MDCX command.
 | 
				
			||||||
 | 
					| crcx:unhandled_param | <<mdcx_crcx:unhandled_param>> | unhandled parameter in MDCX command.
 | 
				
			||||||
 | 
					| mdcx:no_connid | <<mdcx_mdcx:no_connid>> | no connection ID specified in MDCX command.
 | 
				
			||||||
 | 
					| mdcx:conn_not_found | <<mdcx_mdcx:conn_not_found>> | connection specified in MDCX command does not exist.
 | 
				
			||||||
 | 
					| mdcx:invalid_mode | <<mdcx_mdcx:invalid_mode>> | invalid connection mode in MDCX command.
 | 
				
			||||||
 | 
					| mdcx:conn_opt | <<mdcx_mdcx:conn_opt>> | connection options invalid.
 | 
				
			||||||
 | 
					| mdcx:no_remote_conn_desc | <<mdcx_mdcx:no_remote_conn_desc>> | no opposite end specified for connection.
 | 
				
			||||||
 | 
					| mdcx:start_rtp_failure | <<mdcx_mdcx:start_rtp_failure>> | failure to start RTP processing.
 | 
				
			||||||
 | 
					| mdcx:conn_rejected | <<mdcx_mdcx:conn_rejected>> | connection rejected by policy.
 | 
				
			||||||
 | 
					| mdcx:conn_deferred | <<mdcx_mdcx:conn_deferred>> | connection deferred by policy.
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					// rate_ctr_group table crxc statistics
 | 
				
			||||||
 | 
					.crcx - crxc statistics
 | 
				
			||||||
 | 
					[options="header"]
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
 | 
					| Name | Reference | Description
 | 
				
			||||||
 | 
					| crcx:success | <<crcx_crcx:success>> | CRCX command processed successfully.
 | 
				
			||||||
 | 
					| crcx:bad_action | <<crcx_crcx:bad_action>> | bad action in CRCX command.
 | 
				
			||||||
 | 
					| crcx:unhandled_param | <<crcx_crcx:unhandled_param>> | unhandled parameter in CRCX command.
 | 
				
			||||||
 | 
					| crcx:missing_callid | <<crcx_crcx:missing_callid>> | missing CallId in CRCX command.
 | 
				
			||||||
 | 
					| crcx:invalid_mode | <<crcx_crcx:invalid_mode>> | invalid connection mode in CRCX command.
 | 
				
			||||||
 | 
					| crcx:limit_exceeded | <<crcx_crcx:limit_exceeded>> | limit of concurrent connections was reached.
 | 
				
			||||||
 | 
					| crcx:unkown_callid | <<crcx_crcx:unkown_callid>> | unknown CallId in CRCX command.
 | 
				
			||||||
 | 
					| crcx:alloc_conn_fail | <<crcx_crcx:alloc_conn_fail>> | connection allocation failure.
 | 
				
			||||||
 | 
					| crcx:no_remote_conn_desc | <<crcx_crcx:no_remote_conn_desc>> | no opposite end specified for connection.
 | 
				
			||||||
 | 
					| crcx:start_rtp_failure | <<crcx_crcx:start_rtp_failure>> | failure to start RTP processing.
 | 
				
			||||||
 | 
					| crcx:conn_rejected | <<crcx_crcx:conn_rejected>> | connection rejected by policy.
 | 
				
			||||||
 | 
					| crcx:no_osmux | <<crcx_crcx:no_osmux>> | no osmux offered by peer.
 | 
				
			||||||
 | 
					| crcx:conn_opt | <<crcx_crcx:conn_opt>> | connection options invalid.
 | 
				
			||||||
 | 
					| crcx:codec_nego | <<crcx_crcx:codec_nego>> | codec negotiation failure.
 | 
				
			||||||
 | 
					| crcx:bind_port | <<crcx_crcx:bind_port>> | port bind failure.
 | 
				
			||||||
 | 
					|===
 | 
				
			||||||
== Osmo Stat Items
 | 
					== Osmo Stat Items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// generating tables for osmo_stat_items
 | 
					// generating tables for osmo_stat_items
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ indicate collisions or configuration errors.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
==== `X-Osmo-IGN` Format
 | 
					==== `X-Osmo-IGN` Format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The value part of X-Osmo-IGN must be one or more items separated by one or more
 | 
					The value part of `X-Osmo-IGN` must be one or more items separated by one or more
 | 
				
			||||||
spaces. Each item consists of one or more non-whitespace characters.
 | 
					spaces. Each item consists of one or more non-whitespace characters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.Example: `X-Osmo-IGN` format with three ficticious items "X", "abc" and "123".
 | 
					.Example: `X-Osmo-IGN` format with three ficticious items "X", "abc" and "123".
 | 
				
			||||||
@@ -19,7 +19,7 @@ spaces. Each item consists of one or more non-whitespace characters.
 | 
				
			|||||||
X-Osmo-IGN: X abc 123
 | 
					X-Osmo-IGN: X abc 123
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`X-Osmo-IGN` must be issued in the MGCP section (typically as its last item),
 | 
					`X-Osmo-IGN` must be issued in the MGCP header section (typically as its last item),
 | 
				
			||||||
before the SDP section starts.
 | 
					before the SDP section starts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
==== Supported `X-Osmo-IGN` Items
 | 
					==== Supported `X-Osmo-IGN` Items
 | 
				
			||||||
@@ -66,3 +66,7 @@ m=audio 5904 RTP/AVP 97
 | 
				
			|||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:40
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== `X-Osmux`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See <<mgcp-extension-osmux>>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,8 @@ include::{srcdir}/chapters/configuration.adoc[]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include::{srcdir}/chapters/mgcp_extensions.adoc[]
 | 
					include::{srcdir}/chapters/mgcp_extensions.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include::./common/chapters/osmux/osmux.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//include::{srcdir}/chapters/counters.adoc[]
 | 
					//include::{srcdir}/chapters/counters.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/port_numbers.adoc[]
 | 
					include::./common/chapters/port_numbers.adoc[]
 | 
				
			||||||
@@ -29,5 +31,3 @@ include::./common/chapters/bibliography.adoc[]
 | 
				
			|||||||
include::./common/chapters/glossary.adoc[]
 | 
					include::./common/chapters/glossary.adoc[]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include::./common/chapters/gfdl.adoc[]
 | 
					include::./common/chapters/gfdl.adoc[]
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								doc/manuals/regen_doc.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								doc/manuals/regen_doc.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					#!/bin/sh -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -z "$DOCKER_PLAYGROUND" ]; then
 | 
				
			||||||
 | 
						echo "You need to set DOCKER_PLAYGROUND"
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SCRIPT=$(realpath "$0")
 | 
				
			||||||
 | 
					MANUAL_DIR=$(dirname "$SCRIPT")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd "$DOCKER_PLAYGROUND/scripts" || exit 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OSMO_MGW_BRANCH=$COMMIT ./regen_doc.sh osmo-mgw 4243 \
 | 
				
			||||||
 | 
						"$MANUAL_DIR/chapters/counters_generated.adoc" \
 | 
				
			||||||
 | 
						"$MANUAL_DIR/vty/mgw_vty_reference.xml"
 | 
				
			||||||
@@ -187,12 +187,11 @@
 | 
				
			|||||||
        <param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
 | 
					        <param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
    <command id='logging level (rtp|iuup|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
 | 
					    <command id='logging level (rtp|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='logging' doc='Configure logging' />
 | 
					        <param name='logging' doc='Configure logging' />
 | 
				
			||||||
        <param name='level' doc='Set the log level for a specified category' />
 | 
					        <param name='level' doc='Set the log level for a specified category' />
 | 
				
			||||||
        <param name='rtp' doc='RTP stream handling' />
 | 
					        <param name='rtp' doc='RTP stream handling' />
 | 
				
			||||||
        <param name='iuup' doc='IuUP within RTP stream handling' />
 | 
					 | 
				
			||||||
        <param name='lglobal' doc='Library-internal global log family' />
 | 
					        <param name='lglobal' doc='Library-internal global log family' />
 | 
				
			||||||
        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
					        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
				
			||||||
        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
					        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
				
			||||||
@@ -211,6 +210,7 @@
 | 
				
			|||||||
        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
					        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
				
			||||||
        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
					        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
				
			||||||
        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
					        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
				
			||||||
 | 
					        <param name='lrspro' doc='Remote SIM protocol' />
 | 
				
			||||||
        <param name='debug' doc='Log debug messages and higher levels' />
 | 
					        <param name='debug' doc='Log debug messages and higher levels' />
 | 
				
			||||||
        <param name='info' doc='Log informational messages and higher levels' />
 | 
					        <param name='info' doc='Log informational messages and higher levels' />
 | 
				
			||||||
        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
					        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
				
			||||||
@@ -522,12 +522,11 @@
 | 
				
			|||||||
        <param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
 | 
					        <param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
    <command id='logging level (rtp|iuup|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
 | 
					    <command id='logging level (rtp|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='logging' doc='Configure logging' />
 | 
					        <param name='logging' doc='Configure logging' />
 | 
				
			||||||
        <param name='level' doc='Set the log level for a specified category' />
 | 
					        <param name='level' doc='Set the log level for a specified category' />
 | 
				
			||||||
        <param name='rtp' doc='RTP stream handling' />
 | 
					        <param name='rtp' doc='RTP stream handling' />
 | 
				
			||||||
        <param name='iuup' doc='IuUP within RTP stream handling' />
 | 
					 | 
				
			||||||
        <param name='lglobal' doc='Library-internal global log family' />
 | 
					        <param name='lglobal' doc='Library-internal global log family' />
 | 
				
			||||||
        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
					        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
				
			||||||
        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
					        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
				
			||||||
@@ -546,6 +545,7 @@
 | 
				
			|||||||
        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
					        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
				
			||||||
        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
					        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
				
			||||||
        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
					        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
				
			||||||
 | 
					        <param name='lrspro' doc='Remote SIM protocol' />
 | 
				
			||||||
        <param name='debug' doc='Log debug messages and higher levels' />
 | 
					        <param name='debug' doc='Log debug messages and higher levels' />
 | 
				
			||||||
        <param name='info' doc='Log informational messages and higher levels' />
 | 
					        <param name='info' doc='Log informational messages and higher levels' />
 | 
				
			||||||
        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
					        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
				
			||||||
@@ -561,8 +561,7 @@
 | 
				
			|||||||
        <param name='debug' doc='Log debug messages and higher levels' />
 | 
					        <param name='debug' doc='Log debug messages and higher levels' />
 | 
				
			||||||
        <param name='info' doc='Log informational messages and higher levels' />
 | 
					        <param name='info' doc='Log informational messages and higher levels' />
 | 
				
			||||||
        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
					        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
				
			||||||
        <param name='error' doc='Log error messages and higher levels' />
 | 
					        <param name='error' doc='Log error messages and higher levels' />        <param name='fatal' doc='Log only fatal messages' />
 | 
				
			||||||
        <param name='fatal' doc='Log only fatal messages' />
 | 
					 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
    <command id='logging level force-all (debug|info|notice|error|fatal)'>
 | 
					    <command id='logging level force-all (debug|info|notice|error|fatal)'>
 | 
				
			||||||
@@ -1040,12 +1039,11 @@
 | 
				
			|||||||
        <param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
 | 
					        <param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
    <command id='logging level (rtp|iuup|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
 | 
					    <command id='logging level (rtp|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='logging' doc='Configure logging' />
 | 
					        <param name='logging' doc='Configure logging' />
 | 
				
			||||||
        <param name='level' doc='Set the log level for a specified category' />
 | 
					        <param name='level' doc='Set the log level for a specified category' />
 | 
				
			||||||
        <param name='rtp' doc='RTP stream handling' />
 | 
					        <param name='rtp' doc='RTP stream handling' />
 | 
				
			||||||
        <param name='iuup' doc='IuUP within RTP stream handling' />
 | 
					 | 
				
			||||||
        <param name='lglobal' doc='Library-internal global log family' />
 | 
					        <param name='lglobal' doc='Library-internal global log family' />
 | 
				
			||||||
        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
					        <param name='llapd' doc='LAPD in libosmogsm' />
 | 
				
			||||||
        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
					        <param name='linp' doc='A-bis Intput Subsystem' />
 | 
				
			||||||
@@ -1064,6 +1062,7 @@
 | 
				
			|||||||
        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
					        <param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
 | 
				
			||||||
        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
					        <param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
 | 
				
			||||||
        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
					        <param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
 | 
				
			||||||
 | 
					        <param name='lrspro' doc='Remote SIM protocol' />
 | 
				
			||||||
        <param name='debug' doc='Log debug messages and higher levels' />
 | 
					        <param name='debug' doc='Log debug messages and higher levels' />
 | 
				
			||||||
        <param name='info' doc='Log informational messages and higher levels' />
 | 
					        <param name='info' doc='Log informational messages and higher levels' />
 | 
				
			||||||
        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
					        <param name='notice' doc='Log noticeable messages and higher levels' />
 | 
				
			||||||
@@ -1186,10 +1185,11 @@
 | 
				
			|||||||
        <param name='login' doc='Enable password checking' />
 | 
					        <param name='login' doc='Enable password checking' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
    <command id='bind A.B.C.D'>
 | 
					    <command id='bind A.B.C.D [<0-65535>]'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='bind' doc='Accept VTY telnet connections on local interface' />
 | 
					        <param name='bind' doc='Accept VTY telnet connections on local interface' />
 | 
				
			||||||
        <param name='A.B.C.D' doc='Local interface IP address (default: 127.0.0.1)' />
 | 
					        <param name='A.B.C.D' doc='Local interface IP address (default: 127.0.0.1)' />
 | 
				
			||||||
 | 
					        <param name='[<0-65535>]' doc='Local TCP port number' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
  </node>
 | 
					  </node>
 | 
				
			||||||
@@ -1397,6 +1397,19 @@
 | 
				
			|||||||
        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
					        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
 | 
					    <command id='rtp-patch rfc5993hr'>
 | 
				
			||||||
 | 
					      <params>
 | 
				
			||||||
 | 
					        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
				
			||||||
 | 
					        <param name='rfc5993hr' doc='Convert GSM-HR from TS101318 to RFC5993 and vice versa' />
 | 
				
			||||||
 | 
					      </params>
 | 
				
			||||||
 | 
					    </command>
 | 
				
			||||||
 | 
					    <command id='no rtp-patch rfc5993hr'>
 | 
				
			||||||
 | 
					      <params>
 | 
				
			||||||
 | 
					        <param name='no' doc='Negate a command or set its defaults' />
 | 
				
			||||||
 | 
					        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
				
			||||||
 | 
					        <param name='rfc5993hr' doc='Convert GSM-HR from TS101318 to RFC5993 and vice versa' />
 | 
				
			||||||
 | 
					      </params>
 | 
				
			||||||
 | 
					    </command>
 | 
				
			||||||
    <command id='sdp audio fmtp-extra .NAME'>
 | 
					    <command id='sdp audio fmtp-extra .NAME'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='sdp' doc='Add extra fmtp for the SDP file' />
 | 
					        <param name='sdp' doc='Add extra fmtp for the SDP file' />
 | 
				
			||||||
@@ -1496,6 +1509,12 @@
 | 
				
			|||||||
        <param name='NAME' doc='Qualified domain name expected in MGCP endpoint names, or '*' to accept any domain' />
 | 
					        <param name='NAME' doc='Qualified domain name expected in MGCP endpoint names, or '*' to accept any domain' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
 | 
					    <command id='conn-timeout <0-65534>'>
 | 
				
			||||||
 | 
					      <params>
 | 
				
			||||||
 | 
					        <param name='conn-timeout' doc='Set a time after which inactive connections (CIs) are closed. Set to 0 to disable timeout. This can be used to work around interoperability problems causing connections to stay open forever, and slowly exhausting all available ports. Enable keep-alive packets in MGW clients when using this option together with LCLS (OsmoBSC, OsmoMSC: 'rtp keep-alive')!' />
 | 
				
			||||||
 | 
					        <param name='<0-65534>' doc='Timeout value (sec.)' />
 | 
				
			||||||
 | 
					      </params>
 | 
				
			||||||
 | 
					    </command>
 | 
				
			||||||
    <command id='trunk <1-64>'>
 | 
					    <command id='trunk <1-64>'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='trunk' doc='Configure a SS7 trunk' />
 | 
					        <param name='trunk' doc='Configure a SS7 trunk' />
 | 
				
			||||||
@@ -1579,6 +1598,19 @@
 | 
				
			|||||||
        <param name='timestamp' doc='Adjust RTP timestamp' />
 | 
					        <param name='timestamp' doc='Adjust RTP timestamp' />
 | 
				
			||||||
      </params>
 | 
					      </params>
 | 
				
			||||||
    </command>
 | 
					    </command>
 | 
				
			||||||
 | 
					    <command id='rtp-patch rfc5993hr'>
 | 
				
			||||||
 | 
					      <params>
 | 
				
			||||||
 | 
					        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
				
			||||||
 | 
					        <param name='rfc5993hr' doc='Convert GSM-HR from TS101318 to RFC5993 and vice versa' />
 | 
				
			||||||
 | 
					      </params>
 | 
				
			||||||
 | 
					    </command>
 | 
				
			||||||
 | 
					    <command id='no rtp-patch rfc5993hr'>
 | 
				
			||||||
 | 
					      <params>
 | 
				
			||||||
 | 
					        <param name='no' doc='Negate a command or set its defaults' />
 | 
				
			||||||
 | 
					        <param name='rtp-patch' doc='Modify RTP packet header in both directions' />
 | 
				
			||||||
 | 
					        <param name='rfc5993hr' doc='Convert GSM-HR from TS101318 to RFC5993 and vice versa' />
 | 
				
			||||||
 | 
					      </params>
 | 
				
			||||||
 | 
					    </command>
 | 
				
			||||||
    <command id='no rtp-patch timestamp'>
 | 
					    <command id='no rtp-patch timestamp'>
 | 
				
			||||||
      <params>
 | 
					      <params>
 | 
				
			||||||
        <param name='no' doc='Negate a command or set its defaults' />
 | 
					        <param name='no' doc='Negate a command or set its defaults' />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,16 @@ SUBDIRS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
nobase_include_HEADERS = \
 | 
					nobase_include_HEADERS = \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client.h \
 | 
						osmocom/mgcp_client/mgcp_client.h \
 | 
				
			||||||
 | 
						osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
						osmocom/mgcp_client/mgcp_client_fsm.h \
 | 
				
			||||||
	osmocom/mgcp_client/mgcp_common.h \
 | 
					 | 
				
			||||||
	osmocom/mgcp/mgcp.h \
 | 
						osmocom/mgcp/mgcp.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_common.h \
 | 
						osmocom/mgcp/mgcp_common.h \
 | 
				
			||||||
	osmocom/mgcp/mgcp_internal.h \
 | 
						osmocom/mgcp/mgcp_internal.h \
 | 
				
			||||||
	osmocom/mgcp/osmux.h \
 | 
						osmocom/mgcp/osmux.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This gets copied during make from osmocom/mgcp/mgcp_common.h. Therefore it is not included in the source tree and we
 | 
				
			||||||
 | 
					# don't need to distribute it (OS#4084).
 | 
				
			||||||
 | 
					nobase_nodist_include_HEADERS = \
 | 
				
			||||||
 | 
						osmocom/mgcp_client/mgcp_common.h \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,4 +7,6 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_sdp.h \
 | 
						mgcp_sdp.h \
 | 
				
			||||||
	mgcp_codec.h \
 | 
						mgcp_codec.h \
 | 
				
			||||||
	debug.h \
 | 
						debug.h \
 | 
				
			||||||
 | 
						iuup_cn_node.h \
 | 
				
			||||||
 | 
						iuup_protocol.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
/* Debug Areas of the code */
 | 
					/* Debug Areas of the code */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	DRTP,
 | 
						DRTP,
 | 
				
			||||||
 | 
						DIUUP,
 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								include/osmocom/mgcp/iuup_cn_node.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								include/osmocom/mgcp/iuup_cn_node.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
 | 
				
			||||||
 | 
					/* IuUP CN node, minimal implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*                                            _____IuUP_CN_____
 | 
				
			||||||
 | 
					 *                                            |               |
 | 
				
			||||||
 | 
					 * UE <--> RNC --PDU-> osmo_iuup_cn_rx_pdu() -+->           ---+-> rx_payload()
 | 
				
			||||||
 | 
					 *          |                                 |               |
 | 
				
			||||||
 | 
					 *          |  <-PDU-- tx_msg() <-------------+--           <-+--- osmo_iuup_cn_tx_payload()
 | 
				
			||||||
 | 
					 *                                            |               |
 | 
				
			||||||
 | 
					 *                                            -----------------
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_cn_cfg {
 | 
				
			||||||
 | 
						void *node_priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When the IuUP peer sent a voice packet, the clean RTP without the IuUP header is fed to this
 | 
				
			||||||
 | 
						 * callback. */
 | 
				
			||||||
 | 
						osmo_iuup_data_cb_t rx_payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* IuUP handler requests that a PDU shall be sent to the IuUP peer (e.g. the RNC).
 | 
				
			||||||
 | 
						 * It is guaranteed that the msgb->dst pointer is preserved or copied from the msgb that
 | 
				
			||||||
 | 
						 * originated the request. */
 | 
				
			||||||
 | 
						osmo_iuup_data_cb_t tx_msg;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_cn {
 | 
				
			||||||
 | 
						struct osmo_iuup_cn_cfg cfg;
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
						uint8_t next_frame_nr;
 | 
				
			||||||
 | 
						int rtp_payload_type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool osmo_iuup_cn_is_iuup_init(struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
 | 
				
			||||||
 | 
									       const char *name_fmt, ...);
 | 
				
			||||||
 | 
					void osmo_iuup_cn_free(struct osmo_iuup_cn *cn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu);
 | 
				
			||||||
							
								
								
									
										117
									
								
								include/osmocom/mgcp/iuup_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								include/osmocom/mgcp/iuup_protocol.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
 | 
				
			||||||
 | 
					/* IuUP protocol handling, minimal implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/endian.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OSMO_IUUP_HEADROOM 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_iuup_pdu_type {
 | 
				
			||||||
 | 
						OSMO_IUUP_PDU_DATA_WITH_CRC = 0,
 | 
				
			||||||
 | 
						OSMO_IUUP_PDU_CONTROL_PROCEDURE = 14,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_iuup_acknack {
 | 
				
			||||||
 | 
						OSMO_IUUP_ACKNACK_PROCEDURE = 0,
 | 
				
			||||||
 | 
						OSMO_IUUP_ACKNACK_ACK = 1,
 | 
				
			||||||
 | 
						OSMO_IUUP_ACKNACK_NACK = 2,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_iuup_procedure {
 | 
				
			||||||
 | 
						OSMO_IUUP_PROC_INITIALIZATION = 0,
 | 
				
			||||||
 | 
						OSMO_IUUP_PROC_RATE_CONTROL = 1,
 | 
				
			||||||
 | 
						OSMO_IUUP_PROC_TIME_ALIGNMENT = 2,
 | 
				
			||||||
 | 
						OSMO_IUUP_PROC_ERROR_EVENT = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_iuup_frame_good {
 | 
				
			||||||
 | 
						OSMO_IUUP_FRAME_GOOD = 0,
 | 
				
			||||||
 | 
						OSMO_IUUP_FRAME_BAD = 1,
 | 
				
			||||||
 | 
						OSMO_IUUP_FRAME_BAD_DUE_TO_RADIO = 2,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_hdr_ctrl {
 | 
				
			||||||
 | 
					#if OSMO_IS_BIG_ENDIAN
 | 
				
			||||||
 | 
						uint8_t pdu_type:4,
 | 
				
			||||||
 | 
							ack_nack:2,
 | 
				
			||||||
 | 
							frame_nr:2;
 | 
				
			||||||
 | 
						uint8_t mode_version:4,
 | 
				
			||||||
 | 
							procedure:4;
 | 
				
			||||||
 | 
						uint8_t header_crc:6,
 | 
				
			||||||
 | 
							payload_crc_hi:2;
 | 
				
			||||||
 | 
						uint8_t payload_crc_lo;
 | 
				
			||||||
 | 
						uint8_t payload[0];
 | 
				
			||||||
 | 
					#elif OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t frame_nr:2,
 | 
				
			||||||
 | 
							ack_nack:2,
 | 
				
			||||||
 | 
							pdu_type:4;
 | 
				
			||||||
 | 
						uint8_t procedure:4,
 | 
				
			||||||
 | 
							mode_version:4;
 | 
				
			||||||
 | 
						uint8_t payload_crc_hi:2,
 | 
				
			||||||
 | 
							header_crc:6;
 | 
				
			||||||
 | 
						uint8_t payload_crc_lo;
 | 
				
			||||||
 | 
						uint8_t payload[0];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					union osmo_iuup_hdr_ctrl_payload {
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
					#if OSMO_IS_BIG_ENDIAN
 | 
				
			||||||
 | 
						uint8_t spare:3,
 | 
				
			||||||
 | 
							iptis_present:1,
 | 
				
			||||||
 | 
							subflows:3,
 | 
				
			||||||
 | 
							chain:1;
 | 
				
			||||||
 | 
					#elif OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t spare:3,
 | 
				
			||||||
 | 
							iptis_present:1,
 | 
				
			||||||
 | 
							subflows:3,
 | 
				
			||||||
 | 
							chain:1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} initialization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
					#if OSMO_IS_BIG_ENDIAN
 | 
				
			||||||
 | 
						uint8_t error_distance:2,
 | 
				
			||||||
 | 
							error_cause:6;
 | 
				
			||||||
 | 
					#elif OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t error_cause:6,
 | 
				
			||||||
 | 
							error_distance:2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} error_event;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string osmo_iuup_error_cause_names[];
 | 
				
			||||||
 | 
					static inline const char *osmo_iuup_error_cause_name(uint8_t val)
 | 
				
			||||||
 | 
					{ return get_value_string(osmo_iuup_error_cause_names, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_hdr_data {
 | 
				
			||||||
 | 
					#if OSMO_IS_BIG_ENDIAN
 | 
				
			||||||
 | 
						uint8_t pdu_type:4,
 | 
				
			||||||
 | 
							frame_nr:4;
 | 
				
			||||||
 | 
						uint8_t frame_good:2,
 | 
				
			||||||
 | 
							rfci:6;
 | 
				
			||||||
 | 
						uint8_t header_crc:6,
 | 
				
			||||||
 | 
							payload_crc_hi:2;
 | 
				
			||||||
 | 
						uint8_t payload_crc_lo;
 | 
				
			||||||
 | 
					#elif OSMO_IS_LITTLE_ENDIAN
 | 
				
			||||||
 | 
						uint8_t frame_nr:4,
 | 
				
			||||||
 | 
							pdu_type:4;
 | 
				
			||||||
 | 
						uint8_t rfci:6,
 | 
				
			||||||
 | 
							frame_good:2;
 | 
				
			||||||
 | 
						uint8_t payload_crc_hi:2,
 | 
				
			||||||
 | 
							header_crc:6;
 | 
				
			||||||
 | 
						uint8_t payload_crc_lo;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						uint8_t payload[0];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int osmo_iuup_classify(bool log_errors,
 | 
				
			||||||
 | 
							       const char *log_label,
 | 
				
			||||||
 | 
							       struct msgb *pdu,
 | 
				
			||||||
 | 
							       struct osmo_iuup_hdr_ctrl **is_ctrl,
 | 
				
			||||||
 | 
							       struct osmo_iuup_hdr_data **is_data);
 | 
				
			||||||
 | 
					bool osmo_iuup_is_init(struct msgb *pdu);
 | 
				
			||||||
 | 
					void osmo_iuup_make_init_ack(struct msgb *ack);
 | 
				
			||||||
 | 
					void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len);
 | 
				
			||||||
@@ -81,9 +81,10 @@ typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
 | 
				
			|||||||
				     struct mgcp_conn_rtp *conn_dst,
 | 
									     struct mgcp_conn_rtp *conn_dst,
 | 
				
			||||||
				     struct mgcp_conn_rtp *conn_src);
 | 
									     struct mgcp_conn_rtp *conn_src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mgcp_rtp_codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
 | 
					typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
 | 
				
			||||||
				int *payload_type,
 | 
									const struct mgcp_rtp_codec **codec,
 | 
				
			||||||
				const char**subtype_name,
 | 
					 | 
				
			||||||
				const char **fmtp_extra,
 | 
									const char **fmtp_extra,
 | 
				
			||||||
				struct mgcp_conn_rtp *conn);
 | 
									struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,6 +191,7 @@ struct mgcp_trunk_config {
 | 
				
			|||||||
	/* RTP patching */
 | 
						/* RTP patching */
 | 
				
			||||||
	int force_constant_ssrc; /* 0: don't, 1: once */
 | 
						int force_constant_ssrc; /* 0: don't, 1: once */
 | 
				
			||||||
	int force_aligned_timing;
 | 
						int force_aligned_timing;
 | 
				
			||||||
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* spec handling */
 | 
						/* spec handling */
 | 
				
			||||||
	int force_realloc;
 | 
						int force_realloc;
 | 
				
			||||||
@@ -274,6 +276,9 @@ struct mgcp_config {
 | 
				
			|||||||
	uint16_t osmux_dummy;
 | 
						uint16_t osmux_dummy;
 | 
				
			||||||
	/* domain name of the media gateway */
 | 
						/* domain name of the media gateway */
 | 
				
			||||||
	char domain[255+1];
 | 
						char domain[255+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* time after which inactive connections (CIs) get closed */
 | 
				
			||||||
 | 
						int conn_timeout;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* config management */
 | 
					/* config management */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
					void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
					void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name);
 | 
					int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
 | 
				
			||||||
int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
					int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
				
			||||||
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,7 @@ enum mgcp_connection_mode {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
					#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
 | 
				
			||||||
 | 
					#define MGCP_X_OSMO_OSMUX_HEADER "X-Osmux:"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Values should be bitwise-OR-able */
 | 
					/* Values should be bitwise-OR-able */
 | 
				
			||||||
enum mgcp_x_osmo_ign {
 | 
					enum mgcp_x_osmo_ign {
 | 
				
			||||||
@@ -57,6 +58,12 @@ enum mgcp_x_osmo_ign {
 | 
				
			|||||||
	MGCP_X_OSMO_IGN_CALLID = 1,
 | 
						MGCP_X_OSMO_IGN_CALLID = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Codec parameters (communicated via SDP/fmtp) */
 | 
				
			||||||
 | 
					struct mgcp_codec_param {
 | 
				
			||||||
 | 
						bool amr_octet_aligned_present;
 | 
				
			||||||
 | 
						bool amr_octet_aligned;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Ensure that the msg->l2h is NUL terminated. */
 | 
					/* Ensure that the msg->l2h is NUL terminated. */
 | 
				
			||||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
					static inline int mgcp_msg_terminate_nul(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,15 +23,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sockaddr_in;
 | 
					struct sockaddr_in;
 | 
				
			||||||
struct mgcp_conn;
 | 
					struct mgcp_conn;
 | 
				
			||||||
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
struct mgcp_endpoint;
 | 
					struct mgcp_endpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callback type for RTP dispatcher functions
 | 
					struct osmo_rtp_msg_ctx {
 | 
				
			||||||
   (e.g mgcp_dispatch_rtp_bridge_cb, see below) */
 | 
						int proto;
 | 
				
			||||||
typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in *addr,
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
				     char *buf, unsigned int buf_size,
 | 
						struct sockaddr_in *from_addr;
 | 
				
			||||||
				     struct mgcp_conn *conn);
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OSMO_RTP_MSG_CTX(MSGB) (*(struct osmo_rtp_msg_ctx**)&((MSGB)->dst))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_ENDP(endp, level, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DRTP, level, "%x@ " fmt, ENDPOINT_NUMBER(endp), ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).
 | 
				
			||||||
 | 
					 * The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */
 | 
				
			||||||
 | 
					typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callback type for endpoint specific cleanup actions. This function
 | 
					/* Callback type for endpoint specific cleanup actions. This function
 | 
				
			||||||
 * is automatically executed when a connection is freed (see mgcp_conn_free()
 | 
					 * is automatically executed when a connection is freed (see mgcp_conn_free()
 | 
				
			||||||
@@ -99,4 +111,3 @@ struct mgcp_endpoint {
 | 
				
			|||||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
 | 
					#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp);
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,13 @@
 | 
				
			|||||||
#define CONN_ID_BTS "0"
 | 
					#define CONN_ID_BTS "0"
 | 
				
			||||||
#define CONN_ID_NET "1"
 | 
					#define CONN_ID_NET "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CONN(conn, level, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DRTP, level, "(%d@ I:%s) " fmt, \
 | 
				
			||||||
 | 
						     ENDPOINT_NUMBER((conn)->endp), (conn)->id, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
 | 
				
			||||||
 | 
						LOG_CONN(conn_rtp->conn, level, fmt, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum mgcp_trunk_type {
 | 
					enum mgcp_trunk_type {
 | 
				
			||||||
	MGCP_TRUNK_VIRTUAL,
 | 
						MGCP_TRUNK_VIRTUAL,
 | 
				
			||||||
	MGCP_TRUNK_E1,
 | 
						MGCP_TRUNK_E1,
 | 
				
			||||||
@@ -95,6 +102,9 @@ struct mgcp_rtp_codec {
 | 
				
			|||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
	char *audio_name;
 | 
						char *audio_name;
 | 
				
			||||||
	char *subtype_name;
 | 
						char *subtype_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
					/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
 | 
				
			||||||
@@ -128,6 +138,7 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
 | 
						int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
 | 
				
			||||||
	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
						/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
 | 
				
			||||||
	int force_aligned_timing;
 | 
						int force_aligned_timing;
 | 
				
			||||||
 | 
						bool rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Each end has a separate socket for RTP and RTCP */
 | 
						/* Each end has a separate socket for RTP and RTCP */
 | 
				
			||||||
	struct osmo_fd rtp;
 | 
						struct osmo_fd rtp;
 | 
				
			||||||
@@ -184,9 +195,9 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* Osmux state: disabled, activating, active */
 | 
							/* Osmux state: disabled, activating, active */
 | 
				
			||||||
		enum osmux_state state;
 | 
							enum osmux_state state;
 | 
				
			||||||
		/* Allocated Osmux circuit ID for this endpoint */
 | 
							/* Is cid holding valid data? is it allocated from pool? */
 | 
				
			||||||
		int allocated_cid;
 | 
							bool cid_allocated;
 | 
				
			||||||
		/* Used Osmux circuit ID for this endpoint */
 | 
							/* Allocated Osmux circuit ID for this conn */
 | 
				
			||||||
		uint8_t cid;
 | 
							uint8_t cid;
 | 
				
			||||||
		/* handle to batch messages */
 | 
							/* handle to batch messages */
 | 
				
			||||||
		struct osmux_in_handle *in;
 | 
							struct osmux_in_handle *in;
 | 
				
			||||||
@@ -200,6 +211,8 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr_group *rate_ctr_group;
 | 
						struct rate_ctr_group *rate_ctr_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_iuup_cn *iuup;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
@@ -231,6 +244,9 @@ struct mgcp_conn {
 | 
				
			|||||||
	/*! human readable name (vty, logging) */
 | 
						/*! human readable name (vty, logging) */
 | 
				
			||||||
	char name[256];
 | 
						char name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! activity tracker (for cleaning up inactive connections) */
 | 
				
			||||||
 | 
						struct osmo_timer_list watchdog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! union with connection description */
 | 
						/*! union with connection description */
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct mgcp_conn_rtp rtp;
 | 
							struct mgcp_conn_rtp rtp;
 | 
				
			||||||
@@ -259,11 +275,10 @@ struct mgcp_parse_data {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
 | 
					int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
 | 
				
			||||||
	      char *buf, int rc, struct mgcp_conn_rtp *conn_src,
 | 
						      struct msgb *msg, struct mgcp_conn_rtp *conn_src,
 | 
				
			||||||
	      struct mgcp_conn_rtp *conn_dst);
 | 
						      struct mgcp_conn_rtp *conn_dst);
 | 
				
			||||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
					int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
 | 
					int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
 | 
				
			||||||
				unsigned int buf_size, struct mgcp_conn *conn);
 | 
					 | 
				
			||||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
					void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
 | 
				
			||||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
					int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
 | 
				
			||||||
			   struct mgcp_conn_rtp *conn);
 | 
								   struct mgcp_conn_rtp *conn);
 | 
				
			||||||
@@ -294,8 +309,7 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
 | 
				
			|||||||
				      struct mgcp_conn_rtp *conn_src);
 | 
									      struct mgcp_conn_rtp *conn_src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
					void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
				
			||||||
					  int *payload_type,
 | 
										  const struct mgcp_rtp_codec **codec,
 | 
				
			||||||
					  const char**audio_name,
 | 
					 | 
				
			||||||
					  const char **fmtp_extra,
 | 
										  const char **fmtp_extra,
 | 
				
			||||||
					  struct mgcp_conn_rtp *conn);
 | 
										  struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -306,6 +320,11 @@ void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_set_ip_tos(int fd, int tos);
 | 
					int mgcp_set_ip_tos(int fd, int tos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
 | 
					static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
				
			||||||
 | 
						return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	MGCP_DEST_NET = 0,
 | 
						MGCP_DEST_NET = 0,
 | 
				
			||||||
	MGCP_DEST_BTS,
 | 
						MGCP_DEST_BTS,
 | 
				
			||||||
@@ -328,3 +347,19 @@ enum {
 | 
				
			|||||||
#define PTYPE_UNDEFINED (-1)
 | 
					#define PTYPE_UNDEFINED (-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPENDP(endp, cat, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGP(cat, level, "endpoint:0x%x " fmt, \
 | 
				
			||||||
 | 
					     endp ? ENDPOINT_NUMBER(endp) : -1, \
 | 
				
			||||||
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
 | 
					LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
				
			||||||
 | 
					         (conn)->id, \
 | 
				
			||||||
 | 
					         ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
 | 
								  struct sockaddr_in *addr, struct msgb *msg);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,18 +14,20 @@ enum {
 | 
				
			|||||||
int osmux_init(int role, struct mgcp_config *cfg);
 | 
					int osmux_init(int role, struct mgcp_config *cfg);
 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
		      struct in_addr *addr, uint16_t port);
 | 
							      struct in_addr *addr, uint16_t port);
 | 
				
			||||||
void osmux_disable_conn(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
void osmux_allocate_cid(struct mgcp_conn_rtp *conn);
 | 
					int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
 | 
				
			||||||
void osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
 | 
					int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
					int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_get_cid(void);
 | 
					
 | 
				
			||||||
void osmux_put_cid(uint8_t osmux_cid);
 | 
					void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
				
			||||||
int osmux_used_cid(void);
 | 
					int osmux_cid_pool_get_next(void);
 | 
				
			||||||
 | 
					void osmux_cid_pool_put(uint8_t osmux_cid);
 | 
				
			||||||
 | 
					bool osmux_cid_pool_allocated(uint8_t osmux_cid);
 | 
				
			||||||
 | 
					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_NEGOTIATING,  /* Osmux was locally requested in MGCP CRCX */
 | 
					 | 
				
			||||||
	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 osmux_enable_endpoint. */
 | 
				
			||||||
	OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
 | 
						OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,10 @@ enum mgcp_codecs {
 | 
				
			|||||||
 * this is an internal assumption that is made to avoid lookup tables.
 | 
					 * this is an internal assumption that is made to avoid lookup tables.
 | 
				
			||||||
 * The API-User should not rely on this coincidence! */
 | 
					 * The API-User should not rely on this coincidence! */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string osmo_mgcpc_codec_names[];
 | 
				
			||||||
 | 
					static inline const char *osmo_mgcpc_codec_name(enum mgcp_codecs val)
 | 
				
			||||||
 | 
					{ return get_value_string(osmo_mgcpc_codec_names, val); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Structure to build a payload type map to allow the defiition custom payload
 | 
					/*! Structure to build a payload type map to allow the defiition custom payload
 | 
				
			||||||
 *  types. */
 | 
					 *  types. */
 | 
				
			||||||
struct ptmap {
 | 
					struct ptmap {
 | 
				
			||||||
@@ -63,6 +67,8 @@ struct mgcp_response_head {
 | 
				
			|||||||
	char comment[MGCP_COMMENT_MAXLEN];
 | 
						char comment[MGCP_COMMENT_MAXLEN];
 | 
				
			||||||
	char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
						char conn_id[MGCP_CONN_ID_MAXLEN];
 | 
				
			||||||
	char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						uint8_t x_osmo_osmux_cid;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response {
 | 
					struct mgcp_response {
 | 
				
			||||||
@@ -91,6 +97,7 @@ enum mgcp_verb {
 | 
				
			|||||||
#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_IP	0x0008
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
					#define MGCP_MSG_PRESENCE_AUDIO_PORT	0x0010
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
					#define MGCP_MSG_PRESENCE_CONN_MODE	0x0020
 | 
				
			||||||
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
 | 
				
			||||||
#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
					#define MGCP_MSG_PRESENCE_X_OSMO_IGN	0x8000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_msg {
 | 
					struct mgcp_msg {
 | 
				
			||||||
@@ -109,6 +116,10 @@ struct mgcp_msg {
 | 
				
			|||||||
	struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
						struct ptmap ptmap[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int ptmap_len;
 | 
						unsigned int ptmap_len;
 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						int x_osmo_osmux_cid; /* -1 is wildcard */
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
 | 
					void mgcp_client_conf_init(struct mgcp_client_conf *conf);
 | 
				
			||||||
@@ -148,7 +159,7 @@ static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum mgcp_codecs map_str_to_codec(const char *str);
 | 
					enum mgcp_codecs map_str_to_codec(const char *str);
 | 
				
			||||||
unsigned int map_codec_to_pt(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
					unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			||||||
			     enum mgcp_codecs codec);
 | 
								     enum mgcp_codecs codec);
 | 
				
			||||||
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
					enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			||||||
				 unsigned int pt);
 | 
									 unsigned int pt);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								include/osmocom/mgcp_client/mgcp_client_endpoint_fsm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/* FSM to manage multiple connections of an MGW endpoint */
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_fsm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_MGCPC_EP(ep, level, fmt, args...) do { \
 | 
				
			||||||
 | 
						LOGPFSML(ep->fi, level, "%s " fmt, \
 | 
				
			||||||
 | 
							 osmo_mgcpc_ep_name(ep), ## args); \
 | 
				
			||||||
 | 
						} while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep;
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep_ci;
 | 
				
			||||||
 | 
					struct osmo_tdef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,
 | 
				
			||||||
 | 
										  struct mgcp_client *mgcp_client,
 | 
				
			||||||
 | 
										  const struct osmo_tdef *T_defs,
 | 
				
			||||||
 | 
										  const char *fsm_id,
 | 
				
			||||||
 | 
										  const char *endpoint_str_fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep, const char *label_fmt, ...);
 | 
				
			||||||
 | 
					const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);
 | 
				
			||||||
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			||||||
 | 
								      enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
 | 
				
			||||||
 | 
								      struct osmo_fsm_inst *notify,
 | 
				
			||||||
 | 
								      uint32_t event_success, uint32_t event_failure,
 | 
				
			||||||
 | 
								      void *notify_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Dispatch a DLCX for the given connection.
 | 
				
			||||||
 | 
					 * \param ci  Connection identifier as obtained from osmo_mgcpc_ep_ci_add().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_mgcpc_ep_ci_request(ci, MGCP_VERB_DLCX, NULL, NULL, 0, 0, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string osmo_mgcp_verb_names[];
 | 
				
			||||||
 | 
					static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
 | 
				
			||||||
 | 
					{ return get_value_string(osmo_mgcp_verb_names, val); }
 | 
				
			||||||
@@ -47,6 +47,20 @@ struct mgcp_conn_peer {
 | 
				
			|||||||
	 * known to issue incoherent or unknown CallIDs / to issue CRCX commands with a different domain
 | 
						 * known to issue incoherent or unknown CallIDs / to issue CRCX commands with a different domain
 | 
				
			||||||
	 * name than the BSC. An OsmoMGW will then ignore these and not fail on mismatches. */
 | 
						 * name than the BSC. An OsmoMGW will then ignore these and not fail on mismatches. */
 | 
				
			||||||
	uint32_t x_osmo_ign;
 | 
						uint32_t x_osmo_ign;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! send 'X-Osmux: %d' header (or "*" as wildcard). */
 | 
				
			||||||
 | 
						bool x_osmo_osmux_use;
 | 
				
			||||||
 | 
						/*! -1 means send wildcard. */
 | 
				
			||||||
 | 
						int x_osmo_osmux_cid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! If left MGCP_CONN_NONE, use MGCP_CONN_RECV_ONLY or MGCP_CONN_RECV_SEND, depending on whether an audio RTP
 | 
				
			||||||
 | 
						 * address is set. If != MGCP_CONN_NONE, force this conn mode. */
 | 
				
			||||||
 | 
						enum mgcp_connection_mode conn_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! If the codec requires additional format parameters (fmtp), those cann be set here, see also
 | 
				
			||||||
 | 
						 * mgcp_common.h */
 | 
				
			||||||
 | 
						bool param_present;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
					struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
 | 
				
			||||||
@@ -55,3 +69,5 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
 | 
				
			|||||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
					void mgcp_conn_delete(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
 | 
					const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,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=5:0:0
 | 
					MGCP_CLIENT_LIBVERSION=6:0:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -30,6 +30,7 @@ libosmo_mgcp_client_la_SOURCES = \
 | 
				
			|||||||
	mgcp_client.c \
 | 
						mgcp_client.c \
 | 
				
			||||||
	mgcp_client_vty.c \
 | 
						mgcp_client_vty.c \
 | 
				
			||||||
	mgcp_client_fsm.c \
 | 
						mgcp_client_fsm.c \
 | 
				
			||||||
 | 
						mgcp_client_endpoint_fsm.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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,9 +35,16 @@
 | 
				
			|||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef OSMUX_CID_MAX
 | 
				
			||||||
 | 
					#define OSMUX_CID_MAX 255 /* FIXME: use OSMUX_CID_MAX from libosmo-netif? */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Codec descripton for dynamic payload types (SDP) */
 | 
					/* Codec descripton for dynamic payload types (SDP) */
 | 
				
			||||||
static const struct value_string codec_table[] = {
 | 
					const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			||||||
	{ CODEC_PCMU_8000_1, "PCMU/8000/1" },
 | 
						{ CODEC_PCMU_8000_1, "PCMU/8000/1" },
 | 
				
			||||||
	{ CODEC_GSM_8000_1, "GSM/8000/1" },
 | 
						{ CODEC_GSM_8000_1, "GSM/8000/1" },
 | 
				
			||||||
	{ CODEC_PCMA_8000_1, "PCMA/8000/1" },
 | 
						{ CODEC_PCMA_8000_1, "PCMA/8000/1" },
 | 
				
			||||||
@@ -81,19 +88,19 @@ enum mgcp_codecs map_str_to_codec(const char *str)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	osmo_strlcpy(str_buf, extract_codec_name(str), sizeof(str_buf));
 | 
						osmo_strlcpy(str_buf, extract_codec_name(str), sizeof(str_buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(codec_table); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(osmo_mgcpc_codec_names); i++) {
 | 
				
			||||||
		codec_name = extract_codec_name(codec_table[i].str);
 | 
							codec_name = extract_codec_name(osmo_mgcpc_codec_names[i].str);
 | 
				
			||||||
		if (!codec_name)
 | 
							if (!codec_name)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (strcmp(codec_name, str_buf) == 0)
 | 
							if (strcmp(codec_name, str_buf) == 0)
 | 
				
			||||||
			return codec_table[i].value;
 | 
								return osmo_mgcpc_codec_names[i].value;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check the ptmap for illegal mappings */
 | 
					/* Check the ptmap for illegal mappings */
 | 
				
			||||||
static int check_ptmap(struct ptmap *ptmap)
 | 
					static int check_ptmap(const struct ptmap *ptmap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Check if there are mappings that leave the IANA assigned dynamic
 | 
						/* Check if there are mappings that leave the IANA assigned dynamic
 | 
				
			||||||
	 * payload type range. Under normal conditions such mappings should
 | 
						 * payload type range. Under normal conditions such mappings should
 | 
				
			||||||
@@ -122,7 +129,7 @@ error:
 | 
				
			|||||||
 *  \ptmap[in] ptmap_len length of the payload type map.
 | 
					 *  \ptmap[in] ptmap_len length of the payload type map.
 | 
				
			||||||
 *  \ptmap[in] codec the codec for which the payload type should be looked up.
 | 
					 *  \ptmap[in] codec the codec for which the payload type should be looked up.
 | 
				
			||||||
 *  \returns assigned payload type */
 | 
					 *  \returns assigned payload type */
 | 
				
			||||||
unsigned int map_codec_to_pt(struct ptmap *ptmap, unsigned int ptmap_len,
 | 
					unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
 | 
				
			||||||
			     enum mgcp_codecs codec)
 | 
								     enum mgcp_codecs codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
@@ -260,7 +267,8 @@ static bool mgcp_line_is_valid(const char *line)
 | 
				
			|||||||
static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
 | 
					static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *pt_str;
 | 
						char *pt_str;
 | 
				
			||||||
	unsigned int pt;
 | 
						char *pt_end;
 | 
				
			||||||
 | 
						unsigned long int pt;
 | 
				
			||||||
	unsigned int count = 0;
 | 
						unsigned int count = 0;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -284,7 +292,14 @@ static int mgcp_parse_audio_port_pt(struct mgcp_response *r, char *line)
 | 
				
			|||||||
		pt_str = strtok(NULL, " ");
 | 
							pt_str = strtok(NULL, " ");
 | 
				
			||||||
		if (!pt_str)
 | 
							if (!pt_str)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		pt = atoi(pt_str);
 | 
							errno = 0;
 | 
				
			||||||
 | 
							pt = strtoul(pt_str, &pt_end, 0);
 | 
				
			||||||
 | 
							if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
 | 
				
			||||||
 | 
							    pt_str == pt_end)
 | 
				
			||||||
 | 
								goto response_parse_failure_pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
 | 
				
			||||||
 | 
								goto response_parse_failure_pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Do not allow duplicate payload types */
 | 
							/* Do not allow duplicate payload types */
 | 
				
			||||||
		for (i = 0; i < count; i++)
 | 
							for (i = 0; i < count; i++)
 | 
				
			||||||
@@ -322,49 +337,35 @@ static int mgcp_parse_audio_ptime_rtpmap(struct mgcp_response *r, const char *li
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int pt;
 | 
						unsigned int pt;
 | 
				
			||||||
	char codec_resp[64];
 | 
						char codec_resp[64];
 | 
				
			||||||
	unsigned int codec;
 | 
						enum mgcp_codecs codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define A_PTIME "a=ptime:"
 | 
				
			||||||
 | 
					#define A_RTPMAP "a=rtpmap:"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strstr(line, "ptime")) {
 | 
						if (osmo_str_startswith(line, A_PTIME)) {
 | 
				
			||||||
		if (sscanf(line, "a=ptime:%u", &r->ptime) != 1)
 | 
							if (sscanf(line, A_PTIME "%u", &r->ptime) != 1) {
 | 
				
			||||||
			goto response_parse_failure_ptime;
 | 
					 | 
				
			||||||
	} else if (strstr(line, "rtpmap")) {
 | 
					 | 
				
			||||||
		if (sscanf(line, "a=rtpmap:%d %63s", &pt, codec_resp) == 2) {
 | 
					 | 
				
			||||||
			/* The MGW may assign an own payload type in the
 | 
					 | 
				
			||||||
			 * response if the choosen codec falls into the IANA
 | 
					 | 
				
			||||||
			 * assigned dynamic payload type range (96-127).
 | 
					 | 
				
			||||||
			 * Normally the MGW should obey the 3gpp payload type
 | 
					 | 
				
			||||||
			 * assignments, which are fixed, so we likely wont see
 | 
					 | 
				
			||||||
			 * anything unexpected here. In order to be sure that
 | 
					 | 
				
			||||||
			 * we will now check the codec string and if the result
 | 
					 | 
				
			||||||
			 * does not match to what is IANA / 3gpp assigned, we
 | 
					 | 
				
			||||||
			 * will create an entry in the ptmap table so we can
 | 
					 | 
				
			||||||
			 * lookup later what has been assigned. */
 | 
					 | 
				
			||||||
			codec = map_str_to_codec(codec_resp);
 | 
					 | 
				
			||||||
			if (codec != pt) {
 | 
					 | 
				
			||||||
				if (r->ptmap_len < ARRAY_SIZE(r->ptmap)) {
 | 
					 | 
				
			||||||
					r->ptmap[r->ptmap_len].pt = pt;
 | 
					 | 
				
			||||||
					r->ptmap[r->ptmap_len].codec = codec;
 | 
					 | 
				
			||||||
					r->ptmap_len++;
 | 
					 | 
				
			||||||
				} else
 | 
					 | 
				
			||||||
					goto response_parse_failure_rtpmap;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
			goto response_parse_failure_rtpmap;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
response_parse_failure_ptime:
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "Failed to parse SDP parameter, invalid ptime (%s)\n", line);
 | 
								     "Failed to parse SDP parameter, invalid ptime (%s)\n", line);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
response_parse_failure_rtpmap:
 | 
							}
 | 
				
			||||||
 | 
						} else if (osmo_str_startswith(line, A_RTPMAP)) {
 | 
				
			||||||
 | 
							if (sscanf(line, A_RTPMAP "%d %63s", &pt, codec_resp) != 2) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
	     "Failed to parse SDP parameter, invalid rtpmap (%s)\n", line);
 | 
								     "Failed to parse SDP parameter, invalid rtpmap: %s\n", osmo_quote_str(line, -1));
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (r->ptmap_len >= ARRAY_SIZE(r->ptmap)) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR, "No more space in ptmap array (len=%u)\n", r->ptmap_len);
 | 
				
			||||||
 | 
								return -ENOSPC;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							codec = map_str_to_codec(codec_resp);
 | 
				
			||||||
 | 
							r->ptmap[r->ptmap_len].pt = pt;
 | 
				
			||||||
 | 
							r->ptmap[r->ptmap_len].codec = codec;
 | 
				
			||||||
 | 
							r->ptmap_len++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Parse a line like "c=IN IP4 10.11.12.13" */
 | 
					/* Parse a line like "c=IN IP4 10.11.12.13" */
 | 
				
			||||||
static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
 | 
					static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
 | 
				
			||||||
@@ -393,6 +394,37 @@ response_parse_failure:
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
				
			||||||
 | 
					 *  \param[in] line single parameter line from the MGCP message
 | 
				
			||||||
 | 
					 *  \returns OSMUX CID, -1 wildcard, -2 on error
 | 
				
			||||||
 | 
					 * FIXME: This is a copy of function in mgcp_msg.c. Have some common.c file between both libs?
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int mgcp_parse_osmux_cid(const char *line)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int osmux_cid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
				
			||||||
 | 
							     line);
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmux_cid > OSMUX_CID_MAX) { /* OSMUX_CID_MAX from libosmo-netif */
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
				
			||||||
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return osmux_cid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* A new section is marked by a double line break, check a few more
 | 
					/* A new section is marked by a double line break, check a few more
 | 
				
			||||||
 * patterns as there may be variants */
 | 
					 * patterns as there may be variants */
 | 
				
			||||||
static char *mgcp_find_section_end(char *string)
 | 
					static char *mgcp_find_section_end(char *string)
 | 
				
			||||||
@@ -538,7 +570,7 @@ static int parse_head_params(struct mgcp_response *r)
 | 
				
			|||||||
		*data_end = '\0';
 | 
							*data_end = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_non_empty_line(line, data_ptr) {
 | 
						for_each_non_empty_line(line, data_ptr) {
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'Z':
 | 
							case 'Z':
 | 
				
			||||||
			rc = mgcp_parse_head_param(r->head.endpoint,
 | 
								rc = mgcp_parse_head_param(r->head.endpoint,
 | 
				
			||||||
						   sizeof(r->head.endpoint),
 | 
											   sizeof(r->head.endpoint),
 | 
				
			||||||
@@ -567,6 +599,21 @@ static int parse_head_params(struct mgcp_response *r)
 | 
				
			|||||||
			if (rc)
 | 
								if (rc)
 | 
				
			||||||
				goto exit;
 | 
									goto exit;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'X':
 | 
				
			||||||
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
 | 
									rc = mgcp_parse_osmux_cid(line);
 | 
				
			||||||
 | 
									if (rc < 0) {
 | 
				
			||||||
 | 
										/* -1: we don't want wildcards in response. -2: error */
 | 
				
			||||||
 | 
										rc = -EINVAL;
 | 
				
			||||||
 | 
										goto exit;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									r->head.x_osmo_osmux_use = true;
 | 
				
			||||||
 | 
									r->head.x_osmo_osmux_cid = (uint8_t) rc;
 | 
				
			||||||
 | 
									rc = 0;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* skip unhandled parameters */
 | 
								/* skip unhandled parameters */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -828,16 +875,15 @@ const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp)
 | 
				
			|||||||
	return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
 | 
						return mgcp->actual.endpoint_domain_name[0] ? mgcp->actual.endpoint_domain_name : "mgw";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp)
 | 
					static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgcp, char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
						static char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RTPBRIDGE_WILDCARD_FMT "rtpbridge/*@%s"
 | 
						rc = snprintf(endpoint, sizeof(endpoint), "%s@%s", name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
	rc = snprintf(endpoint, sizeof(endpoint), RTPBRIDGE_WILDCARD_FMT, mgcp_client_endpoint_domain(mgcp));
 | 
					 | 
				
			||||||
	if (rc > sizeof(endpoint) - 1) {
 | 
						if (rc > sizeof(endpoint) - 1) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '" RTPBRIDGE_WILDCARD_FMT "'\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "MGCP endpoint exceeds maximum length of %zu: '%s@%s'\n",
 | 
				
			||||||
		     sizeof(endpoint) - 1, mgcp_client_endpoint_domain(mgcp));
 | 
							     sizeof(endpoint) - 1, name, mgcp_client_endpoint_domain(mgcp));
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (rc < 1) {
 | 
						if (rc < 1) {
 | 
				
			||||||
@@ -847,6 +893,11 @@ const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp)
 | 
				
			|||||||
	return endpoint;
 | 
						return endpoint;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return _mgcp_client_name_append_domain(mgcp, "rtpbridge/*");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_response_pending * mgcp_client_pending_add(
 | 
					struct mgcp_response_pending * mgcp_client_pending_add(
 | 
				
			||||||
					struct mgcp_client *mgcp,
 | 
										struct mgcp_client *mgcp,
 | 
				
			||||||
					mgcp_trans_id_t trans_id,
 | 
										mgcp_trans_id_t trans_id,
 | 
				
			||||||
@@ -978,7 +1029,7 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
		rc += msgb_printf(msg, " a:");
 | 
							rc += msgb_printf(msg, " a:");
 | 
				
			||||||
		for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
							for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
			pt = mgcp_msg->codecs[i];
 | 
								pt = mgcp_msg->codecs[i];
 | 
				
			||||||
			codec = get_value_string_or_null(codec_table, pt);
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, pt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
@@ -1051,6 +1102,20 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	rc += msgb_printf(msg, "\r\n");
 | 
						rc += msgb_printf(msg, "\r\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add optional codec parameters (fmtp) */
 | 
				
			||||||
 | 
						if (mgcp_msg->param_present) {
 | 
				
			||||||
 | 
							for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
 | 
								/* The following is only applicable for AMR */
 | 
				
			||||||
 | 
								if (mgcp_msg->codecs[i] != CODEC_AMR_8000_1 && mgcp_msg->codecs[i] != CODEC_AMRWB_16000_1)
 | 
				
			||||||
 | 
									   continue;
 | 
				
			||||||
 | 
								pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
 | 
								if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
 | 
									rc += msgb_printf(msg, "a=fmtp:%u octet-align=1\r\n", pt);
 | 
				
			||||||
 | 
								else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned)
 | 
				
			||||||
 | 
									rc += msgb_printf(msg, "a=fmtp:%u octet-align=0\r\n", pt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
						for (i = 0; i < mgcp_msg->codecs_len; i++) {
 | 
				
			||||||
		pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
							pt = map_codec_to_pt(mgcp_msg->ptmap, mgcp_msg->ptmap_len, mgcp_msg->codecs[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1058,7 +1123,7 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie
 | 
				
			|||||||
		 * require to be explained further via rtpmap. All others
 | 
							 * require to be explained further via rtpmap. All others
 | 
				
			||||||
		 * are implcitly definedby the number in m=audio */
 | 
							 * are implcitly definedby the number in m=audio */
 | 
				
			||||||
		if (pt >= 96 && pt <= 127) {
 | 
							if (pt >= 96 && pt <= 127) {
 | 
				
			||||||
			codec = get_value_string_or_null(codec_table, mgcp_msg->codecs[i]);
 | 
								codec = get_value_string_or_null(osmo_mgcpc_codec_names, mgcp_msg->codecs[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Note: Use codec descriptors from enum mgcp_codecs
 | 
								/* Note: Use codec descriptors from enum mgcp_codecs
 | 
				
			||||||
			 * in mgcp_client only! */
 | 
								 * in mgcp_client only! */
 | 
				
			||||||
@@ -1086,6 +1151,7 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
	int rc_sdp;
 | 
						int rc_sdp;
 | 
				
			||||||
	bool use_sdp = false;
 | 
						bool use_sdp = false;
 | 
				
			||||||
 | 
						char buf[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg->l2h = msg->data;
 | 
						msg->l2h = msg->data;
 | 
				
			||||||
	msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
 | 
						msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
 | 
				
			||||||
@@ -1189,6 +1255,22 @@ struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
 | 
				
			|||||||
		    msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
							    msgb_printf(msg, MGCP_X_OSMO_IGN_HEADER "%s\r\n",
 | 
				
			||||||
				mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
									mgcp_msg->x_osmo_ign & MGCP_X_OSMO_IGN_CALLID ? " C": "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Add X-Osmo-Osmux */
 | 
				
			||||||
 | 
						if ((mgcp_msg->presence & MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID)) {
 | 
				
			||||||
 | 
							if (mgcp_msg->x_osmo_osmux_cid < -1 || mgcp_msg->x_osmo_osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "Wrong Osmux CID %d, can not generate MGCP message\n",
 | 
				
			||||||
 | 
								     mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), " %d", mgcp_msg->x_osmo_osmux_cid);
 | 
				
			||||||
 | 
							rc +=
 | 
				
			||||||
 | 
							    msgb_printf(msg, MGCP_X_OSMO_OSMUX_HEADER "%s\r\n",
 | 
				
			||||||
 | 
									mgcp_msg->x_osmo_osmux_cid == -1 ? " *": buf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Add session description protocol (SDP) */
 | 
						/* Add session description protocol (SDP) */
 | 
				
			||||||
	if (use_sdp
 | 
						if (use_sdp
 | 
				
			||||||
	    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
						    && (mgcp_msg->verb == MGCP_VERB_CRCX
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										886
									
								
								src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										886
									
								
								src/libosmo-mgcp-client/mgcp_client_endpoint_fsm.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,886 @@
 | 
				
			|||||||
 | 
					/* FSM to manage multiple connections of an MGW endpoint
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * (C) 2018-2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Neels Hofmeyr <neels@hofmeyr.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <sys/socket.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/byteswap.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/tdef.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CI(ci, level, fmt, args...) do { \
 | 
				
			||||||
 | 
						if (!ci || !ci->ep) \
 | 
				
			||||||
 | 
							LOGP(DLGLOBAL, level, "(unknown MGW endpoint) " fmt, ## args); \
 | 
				
			||||||
 | 
						else \
 | 
				
			||||||
 | 
							LOG_MGCPC_EP(ci->ep, level, "CI[%d] %s%s%s: " fmt, \
 | 
				
			||||||
 | 
								(int)(ci - ci->ep->ci), \
 | 
				
			||||||
 | 
								ci->label ? : "-", \
 | 
				
			||||||
 | 
								ci->mgcp_ci_str[0] ? " CI=" : "", \
 | 
				
			||||||
 | 
								ci->mgcp_ci_str[0] ? ci->mgcp_ci_str : "", \
 | 
				
			||||||
 | 
								## args); \
 | 
				
			||||||
 | 
						} while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_CI_VERB(ci, level, fmt, args...) do { \
 | 
				
			||||||
 | 
						if (ci->verb_info.addr[0]) \
 | 
				
			||||||
 | 
							LOG_CI(ci, level, "%s %s:%u: " fmt, \
 | 
				
			||||||
 | 
								osmo_mgcp_verb_name(ci->verb), ci->verb_info.addr, ci->verb_info.port, \
 | 
				
			||||||
 | 
								## args); \
 | 
				
			||||||
 | 
						else \
 | 
				
			||||||
 | 
							LOG_CI(ci, level, "%s: " fmt, \
 | 
				
			||||||
 | 
								osmo_mgcp_verb_name(ci->verb), \
 | 
				
			||||||
 | 
								## args); \
 | 
				
			||||||
 | 
						} while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_mgcpc_ep_fsm_state {
 | 
				
			||||||
 | 
						OSMO_MGCPC_EP_ST_UNUSED = 0,
 | 
				
			||||||
 | 
						OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE,
 | 
				
			||||||
 | 
						OSMO_MGCPC_EP_ST_IN_USE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum osmo_mgcpc_ep_fsm_event {
 | 
				
			||||||
 | 
						_OSMO_MGCPC_EP_EV_LAST = 0,
 | 
				
			||||||
 | 
						/* and MGW response events are allocated dynamically */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FIRST_CI_EVENT (_OSMO_MGCPC_EP_EV_LAST + (_OSMO_MGCPC_EP_EV_LAST & 1)) /* rounded up to even nr */
 | 
				
			||||||
 | 
					#define USABLE_CI ((32 - FIRST_CI_EVENT)/2)
 | 
				
			||||||
 | 
					#define EV_TO_CI_IDX(event) ((event - FIRST_CI_EVENT) / 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CI_EV_SUCCESS(ci) (FIRST_CI_EVENT + (((ci) - ci->ep->ci) * 2))
 | 
				
			||||||
 | 
					#define CI_EV_FAILURE(ci) (CI_EV_SUCCESS(ci) + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct osmo_fsm osmo_mgcpc_ep_fsm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! One connection on an endpoint, corresponding to a connection identifier (CI) as returned by the MGW.
 | 
				
			||||||
 | 
					 * An endpoint has a fixed number of slots of these, which may or may not be in use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep_ci {
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool occupied;
 | 
				
			||||||
 | 
						char label[64];
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *mgcp_client_fi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool pending;
 | 
				
			||||||
 | 
						bool sent;
 | 
				
			||||||
 | 
						enum mgcp_verb verb;
 | 
				
			||||||
 | 
						struct mgcp_conn_peer verb_info;
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *notify;
 | 
				
			||||||
 | 
						uint32_t notify_success;
 | 
				
			||||||
 | 
						uint32_t notify_failure;
 | 
				
			||||||
 | 
						void *notify_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool got_port_info;
 | 
				
			||||||
 | 
						struct mgcp_conn_peer rtp_info;
 | 
				
			||||||
 | 
						char mgcp_ci_str[MGCP_CONN_ID_LENGTH];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! An MGW endpoint with N connections, like "rtpbridge/23@mgw". */
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep {
 | 
				
			||||||
 | 
						/*! MGCP client connection to the MGW. */
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp_client;
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! Endpoint string; at first this might be a wildcard, and upon the first CRCX OK response, this will reflect
 | 
				
			||||||
 | 
						 * the endpoint name returned by the MGW. */
 | 
				
			||||||
 | 
						char endpoint[MGCP_ENDPOINT_MAXLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! Timeout definitions used for this endpoint, see osmo_mgcpc_ep_fsm_timeouts. */
 | 
				
			||||||
 | 
						const struct osmo_tdef *T_defs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! True as soon as the first CRCX OK is received. The endpoint name may be determined by the first CRCX
 | 
				
			||||||
 | 
						 * response, so to dispatch any other messages, the FSM instance *must* wait for the first CRCX OK to arrive
 | 
				
			||||||
 | 
						 * first. Once the endpoint name is pinpointed, any amount of operations may be dispatched concurrently. */
 | 
				
			||||||
 | 
						bool first_crcx_complete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*! Endpoint connection slots. Note that each connection has its own set of FSM event numbers to signal success
 | 
				
			||||||
 | 
						 * and failure, depending on its index within this array. See CI_EV_SUCCESS and CI_EV_FAILURE. */
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep_ci ci[USABLE_CI];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct value_string osmo_mgcp_verb_names[] = {
 | 
				
			||||||
 | 
						{ MGCP_VERB_CRCX, "CRCX" },
 | 
				
			||||||
 | 
						{ MGCP_VERB_MDCX, "MDCX" },
 | 
				
			||||||
 | 
						{ MGCP_VERB_DLCX, "DLCX" },
 | 
				
			||||||
 | 
						{ MGCP_VERB_AUEP, "AUEP" },
 | 
				
			||||||
 | 
						{ MGCP_VERB_RSIP, "RSIP" },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmo_mgcpc_ep_count(struct osmo_mgcpc_ep *ep, int *occupied, int *pending_not_sent,
 | 
				
			||||||
 | 
									int *waiting_for_response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_check_ci(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ci)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						if (!ci->ep)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						if (ci < ci->ep->ci || ci >= &ci->ep->ci[USABLE_CI])
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return ci;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_for_event(struct osmo_mgcpc_ep *ep, uint32_t event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int idx;
 | 
				
			||||||
 | 
						if (event < FIRST_CI_EVENT)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						idx = EV_TO_CI_IDX(event);
 | 
				
			||||||
 | 
						if (idx >= sizeof(ep->ci))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return osmo_mgcpc_ep_check_ci(&ep->ci[idx]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ep)
 | 
				
			||||||
 | 
							return "NULL";
 | 
				
			||||||
 | 
						if (ep->endpoint[0])
 | 
				
			||||||
 | 
							return ep->endpoint;
 | 
				
			||||||
 | 
						return osmo_fsm_inst_name(ep->fi);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *mgcp_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
				
			||||||
 | 
						 * this buffer is too small. */
 | 
				
			||||||
 | 
						static char buf[1024];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!info)
 | 
				
			||||||
 | 
							return "NULL";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->endpoint[0]
 | 
				
			||||||
 | 
						    && info->addr[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s:%s:%u",
 | 
				
			||||||
 | 
								 info->endpoint, info->addr, info->port);
 | 
				
			||||||
 | 
						else if (info->endpoint[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s", info->endpoint);
 | 
				
			||||||
 | 
						else if (info->addr[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s:%u", info->addr, info->port);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return "empty";
 | 
				
			||||||
 | 
						return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_conn_peer *rtp_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ci)
 | 
				
			||||||
 | 
							return "NULL";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rtp_info)
 | 
				
			||||||
 | 
							return mgcp_conn_peer_name(rtp_info);
 | 
				
			||||||
 | 
						return osmo_mgcpc_ep_name(ci->ep);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ci || !ci->mgcp_ci_str[0])
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return ci->mgcp_ci_str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void fill_event_names()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
				
			||||||
 | 
							if (i < _OSMO_MGCPC_EP_EV_LAST)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (i < FIRST_CI_EVENT || EV_TO_CI_IDX(i) > USABLE_CI) {
 | 
				
			||||||
 | 
								osmo_mgcpc_ep_fsm_event_names[i] = (struct value_string){i, "Unused"};
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							snprintf(osmo_mgcpc_ep_fsm_event_name_bufs[i], sizeof(osmo_mgcpc_ep_fsm_event_name_bufs[i]),
 | 
				
			||||||
 | 
								 "MGW Response for CI #%d", EV_TO_CI_IDX(i));
 | 
				
			||||||
 | 
							osmo_mgcpc_ep_fsm_event_names[i] = (struct value_string){i, osmo_mgcpc_ep_fsm_event_name_bufs[i]};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* T_defs is used to obtain an (Osmocom specific) T2427001: timeout for an MGCP response (note, 2427 corresponds to the
 | 
				
			||||||
 | 
					 * default MGCP port in osmo-mgw). */
 | 
				
			||||||
 | 
					static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
				
			||||||
 | 
						fill_event_names();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep *osmo_mgcpc_ep_fi_mgwep(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(fi);
 | 
				
			||||||
 | 
						OSMO_ASSERT(fi->fsm == &osmo_mgcpc_ep_fsm);
 | 
				
			||||||
 | 
						OSMO_ASSERT(fi->priv);
 | 
				
			||||||
 | 
						return fi->priv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Allocate an osmo_mgcpc_ep FSM.
 | 
				
			||||||
 | 
					 * MGCP messages to set up the endpoint will be sent on the given mgcp_client, as soon as the first
 | 
				
			||||||
 | 
					 * osmo_mgcpc_ep_ci_request() is invoked.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A typical sequence of events would be:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    ep = osmo_mgcpc_ep_alloc(..., mgcp_client_rtpbridge_wildcard(client));
 | 
				
			||||||
 | 
					 *    ci_to_ran = osmo_mgcpc_ep_ci_add(ep);
 | 
				
			||||||
 | 
					 *    osmo_mgcpc_ep_ci_request(ci_to_ran, MGCP_VERB_CRCX, verb_info,
 | 
				
			||||||
 | 
					 *                             my_call_fsm, MY_EVENT_MGCP_OK, MY_EVENT_MGCP_FAIL);
 | 
				
			||||||
 | 
					 *    ci_to_cn = osmo_mgcpc_ep_ci_add(ep);
 | 
				
			||||||
 | 
					 *    osmo_mgcpc_ep_ci_request(ci_to_cn, MGCP_VERB_CRCX, verb_info,
 | 
				
			||||||
 | 
					 *                             my_call_fsm, MY_EVENT_MGCP_OK, MY_EVENT_MGCP_FAIL);
 | 
				
			||||||
 | 
					 *    ...
 | 
				
			||||||
 | 
					 *    osmo_mgcpc_ep_ci_request(ci_to_ran, MGCP_VERB_MDCX, ...);
 | 
				
			||||||
 | 
					 *    ...
 | 
				
			||||||
 | 
					 *    osmo_mgcpc_ep_clear(ep);
 | 
				
			||||||
 | 
					 *    ep = NULL;
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param parent  Parent FSM.
 | 
				
			||||||
 | 
					 * \param parent_term_event  Event to dispatch to the parent on termination of this FSM instance.
 | 
				
			||||||
 | 
					 * \param mgcp_client  Connection to the MGW.
 | 
				
			||||||
 | 
					 * \param T_defs  Timeout definitions to be used for FSM states, see osmo_mgcpc_ep_fsm_timeouts.
 | 
				
			||||||
 | 
					 * \param fsm_id  FSM instance ID.
 | 
				
			||||||
 | 
					 * \param endpoint_str_fmt  The endpoint string format to send to the MGW upon the first CRCX.
 | 
				
			||||||
 | 
					 *                          See mgcp_client_rtpbridge_wildcard() for "rtpbridge" endpoints.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,
 | 
				
			||||||
 | 
										  struct mgcp_client *mgcp_client,
 | 
				
			||||||
 | 
										  const struct osmo_tdef *T_defs,
 | 
				
			||||||
 | 
										  const char *fsm_id,
 | 
				
			||||||
 | 
										  const char *endpoint_str_fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_client)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fi = osmo_fsm_inst_alloc_child(&osmo_mgcpc_ep_fsm, parent, parent_term_event);
 | 
				
			||||||
 | 
						OSMO_ASSERT(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_fsm_inst_update_id(fi, fsm_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ep = talloc_zero(fi, struct osmo_mgcpc_ep);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*ep = (struct osmo_mgcpc_ep){
 | 
				
			||||||
 | 
							.mgcp_client = mgcp_client,
 | 
				
			||||||
 | 
							.fi = fi,
 | 
				
			||||||
 | 
							.T_defs = T_defs,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						fi->priv = ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, endpoint_str_fmt);
 | 
				
			||||||
 | 
						rc = vsnprintf(ep->endpoint, sizeof(ep->endpoint), endpoint_str_fmt ? : "", ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc <= 0 || rc >= sizeof(ep->endpoint)) {
 | 
				
			||||||
 | 
							LOG_MGCPC_EP(ep, LOGL_ERROR, "Endpoint name too long or too short: %s\n",
 | 
				
			||||||
 | 
								  ep->endpoint);
 | 
				
			||||||
 | 
							osmo_fsm_inst_term(ep->fi, OSMO_FSM_TERM_ERROR, 0);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ep;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Add a connection to an endpoint.
 | 
				
			||||||
 | 
					 * Allocate a connection identifier slot in the osmo_mgcpc_ep instance, do not yet dispatch a CRCX.
 | 
				
			||||||
 | 
					 * The CRCX is dispatched only upon the first osmo_mgcpc_ep_ci_request().
 | 
				
			||||||
 | 
					 * \param ep  Parent endpoint instance.
 | 
				
			||||||
 | 
					 * \param label_fmt  Label for logging.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep,
 | 
				
			||||||
 | 
										      const char *label_fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep_ci *ci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < USABLE_CI; i++) {
 | 
				
			||||||
 | 
							ci = &ep->ci[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ci->occupied || ci->mgcp_client_fi)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*ci = (struct osmo_mgcpc_ep_ci){
 | 
				
			||||||
 | 
								.ep = ep,
 | 
				
			||||||
 | 
								.occupied = true,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							if (label_fmt) {
 | 
				
			||||||
 | 
								va_start(ap, label_fmt);
 | 
				
			||||||
 | 
								vsnprintf(ci->label, sizeof(ci->label), label_fmt, ap);
 | 
				
			||||||
 | 
								va_end(ap);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return ci;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_MGCPC_EP(ep, LOGL_ERROR,
 | 
				
			||||||
 | 
							  "Cannot allocate another endpoint, all "
 | 
				
			||||||
 | 
							  OSMO_STRINGIFY_VAL(USABLE_CI) " are in use\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool osmo_mgcpc_ep_fsm_check_state_chg_after_response(struct osmo_fsm_inst *fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void on_failure(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *notify = ci->notify;
 | 
				
			||||||
 | 
						uint32_t notify_failure = ci->notify_failure;
 | 
				
			||||||
 | 
						void *notify_data = ci->notify_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ci->occupied)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*ci = (struct osmo_mgcpc_ep_ci){
 | 
				
			||||||
 | 
							.ep = ci->ep,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If this check has terminated the FSM instance, don't fire any more events to prevent use-after-free problems.
 | 
				
			||||||
 | 
						 * The endpoint FSM does dispatch a term event to its parent, and everything should be cleaned like that. */
 | 
				
			||||||
 | 
						if (!osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (notify)
 | 
				
			||||||
 | 
							osmo_fsm_inst_dispatch(notify, notify_failure, notify_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int update_endpoint_name(struct osmo_mgcpc_ep_ci *ci, const char *new_endpoint_name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = ci->ep;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!strcmp(ep->endpoint, new_endpoint_name)) {
 | 
				
			||||||
 | 
							/* Same endpoint name, nothing to do. */
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The endpoint name should only change on the very first CRCX response. */
 | 
				
			||||||
 | 
						if (ep->first_crcx_complete) {
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_ERROR, "Reponse returned mismatching endpoint name."
 | 
				
			||||||
 | 
							       " This is endpoint %s, instead received %s\n",
 | 
				
			||||||
 | 
							       ep->endpoint, new_endpoint_name);
 | 
				
			||||||
 | 
							on_failure(ci);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* This is the first CRCX response, update endpoint name. */
 | 
				
			||||||
 | 
						rc = OSMO_STRLCPY_ARRAY(ep->endpoint, new_endpoint_name);
 | 
				
			||||||
 | 
						if (rc <= 0 || rc >= sizeof(ep->endpoint)) {
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_ERROR, "Unable to copy endpoint name %s\n", osmo_quote_str(new_endpoint_name, -1));
 | 
				
			||||||
 | 
							osmo_mgcpc_ep_ci_dlcx(ci);
 | 
				
			||||||
 | 
							on_failure(ci);
 | 
				
			||||||
 | 
							return -ENOSPC;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure already pending requests use this updated endpoint name. */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
 | 
				
			||||||
 | 
							struct osmo_mgcpc_ep_ci *other_ci = &ep->ci[i];
 | 
				
			||||||
 | 
							if (!other_ci->occupied)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (!other_ci->pending)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (other_ci->sent)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							OSMO_STRLCPY_ARRAY(other_ci->verb_info.endpoint, ep->endpoint);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void on_success(struct osmo_mgcpc_ep_ci *ci, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn_peer *rtp_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ci->occupied)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ci->pending = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ci->verb) {
 | 
				
			||||||
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
 | 
							/* If we sent a wildcarded endpoint name on CRCX, we need to store the resulting endpoint
 | 
				
			||||||
 | 
							 * name here. Also, we receive the MGW's RTP port information. */
 | 
				
			||||||
 | 
							rtp_info = data;
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtp_info);
 | 
				
			||||||
 | 
							ci->got_port_info = true;
 | 
				
			||||||
 | 
							ci->rtp_info = *rtp_info;
 | 
				
			||||||
 | 
							osmo_strlcpy(ci->mgcp_ci_str, mgcp_conn_get_ci(ci->mgcp_client_fi),
 | 
				
			||||||
 | 
								sizeof(ci->mgcp_ci_str));
 | 
				
			||||||
 | 
							if (rtp_info->endpoint[0]) {
 | 
				
			||||||
 | 
								/* On errors, this instance might already be deallocated. Make sure to not access anything after
 | 
				
			||||||
 | 
								 * error. */
 | 
				
			||||||
 | 
								if (update_endpoint_name(ci, rtp_info->endpoint))
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ci->ep->first_crcx_complete = true;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_CI(ci, LOGL_DEBUG, "received successful response to %s: RTP=%s%s\n",
 | 
				
			||||||
 | 
						       osmo_mgcp_verb_name(ci->verb),
 | 
				
			||||||
 | 
						       mgcp_conn_peer_name(ci->got_port_info? &ci->rtp_info : NULL),
 | 
				
			||||||
 | 
						       ci->notify ? "" : " (not sending a notification)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ci->notify)
 | 
				
			||||||
 | 
							osmo_fsm_inst_dispatch(ci->notify, ci->notify_success, ci->notify_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_mgcpc_ep_fsm_check_state_chg_after_response(ci->ep->fi);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
 | 
				
			||||||
 | 
					const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ci = osmo_mgcpc_ep_check_ci((struct osmo_mgcpc_ep_ci*)ci);
 | 
				
			||||||
 | 
						if (!ci)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						if (!ci->got_port_info)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return &ci->rtp_info;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Return the MGW's RTP port information for this connection, as returned by the last CRCX/MDCX OK message. */
 | 
				
			||||||
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_conn_peer *rtp_info;
 | 
				
			||||||
 | 
						struct sockaddr_in *sin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 | 
				
			||||||
 | 
						if (!rtp_info)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sin = (struct sockaddr_in *)dest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sin->sin_family = AF_INET;
 | 
				
			||||||
 | 
					        sin->sin_addr.s_addr = inet_addr(rtp_info->addr);
 | 
				
			||||||
 | 
					        sin->sin_port = osmo_ntohs(rtp_info->port);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_conn_peer *rtp_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_info = osmo_mgcpc_ep_ci_get_rtp_info(ci);
 | 
				
			||||||
 | 
						if (!rtp_info)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rtp_info->x_osmo_osmux_use)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*cid = rtp_info->x_osmo_osmux_cid;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_tdef_state_timeout osmo_mgcpc_ep_fsm_timeouts[32] = {
 | 
				
			||||||
 | 
						[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = { .T=2427001 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.
 | 
				
			||||||
 | 
					 * The actual timeout value is in turn obtained from osmo_mgcpc_ep.T_defs.
 | 
				
			||||||
 | 
					 * Assumes local variable fi exists. */
 | 
				
			||||||
 | 
					#define osmo_mgcpc_ep_fsm_state_chg(state) \
 | 
				
			||||||
 | 
						osmo_tdef_fsm_inst_state_chg(fi, state, osmo_mgcpc_ep_fsm_timeouts, \
 | 
				
			||||||
 | 
									     ((struct osmo_mgcpc_ep*)fi->priv)->T_defs, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Dispatch an actual CRCX/MDCX/DLCX message for this connection.
 | 
				
			||||||
 | 
					 * \param ci  Connection identifier as obtained from osmo_mgcpc_ep_ci_add().
 | 
				
			||||||
 | 
					 * \param verb  MGCP operation to dispatch.
 | 
				
			||||||
 | 
					 * \param verb_info  Parameters for the MGCP operation.
 | 
				
			||||||
 | 
					 * \param notify  Peer FSM instance to notify of completed/failed operation.
 | 
				
			||||||
 | 
					 * \param event_success  Which event to dispatch to 'notify' upon OK response.
 | 
				
			||||||
 | 
					 * \param event_failure  Which event to dispatch to 'notify' upon failure response.
 | 
				
			||||||
 | 
					 * \param notify_data  Data pointer to pass to the event dispatch for both success and failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
 | 
				
			||||||
 | 
								      enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
 | 
				
			||||||
 | 
								      struct osmo_fsm_inst *notify,
 | 
				
			||||||
 | 
								      uint32_t event_success, uint32_t event_failure,
 | 
				
			||||||
 | 
								      void *notify_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep;
 | 
				
			||||||
 | 
						struct osmo_fsm_inst *fi;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep_ci cleared_ci;
 | 
				
			||||||
 | 
						ci = osmo_mgcpc_ep_check_ci(ci);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ci) {
 | 
				
			||||||
 | 
							LOGP(DLGLOBAL, LOGL_ERROR, "Invalid MGW endpoint request: no ci\n");
 | 
				
			||||||
 | 
							goto dispatch_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!verb_info && verb != MGCP_VERB_DLCX) {
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_ERROR, "Invalid MGW endpoint request: missing verb details for %s\n",
 | 
				
			||||||
 | 
							       osmo_mgcp_verb_name(verb));
 | 
				
			||||||
 | 
							goto dispatch_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ((verb < 0) || (verb > MGCP_VERB_RSIP)) {
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_ERROR, "Invalid MGW endpoint request: unknown verb: %s\n",
 | 
				
			||||||
 | 
							       osmo_mgcp_verb_name(verb));
 | 
				
			||||||
 | 
							goto dispatch_error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ep = ci->ep;
 | 
				
			||||||
 | 
						fi = ep->fi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear volatile state by explicitly keeping those that should remain. Because we can't assign
 | 
				
			||||||
 | 
						 * the char[] directly, dance through cleared_ci and copy back. */
 | 
				
			||||||
 | 
						cleared_ci = (struct osmo_mgcpc_ep_ci){
 | 
				
			||||||
 | 
							.ep = ep,
 | 
				
			||||||
 | 
							.mgcp_client_fi = ci->mgcp_client_fi,
 | 
				
			||||||
 | 
							.got_port_info = ci->got_port_info,
 | 
				
			||||||
 | 
							.rtp_info = ci->rtp_info,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							.occupied = true,
 | 
				
			||||||
 | 
							/* .pending = true follows below */
 | 
				
			||||||
 | 
							.verb = verb,
 | 
				
			||||||
 | 
							.notify = notify,
 | 
				
			||||||
 | 
							.notify_success = event_success,
 | 
				
			||||||
 | 
							.notify_failure = event_failure,
 | 
				
			||||||
 | 
							.notify_data = notify_data,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						osmo_strlcpy(cleared_ci.label, ci->label, sizeof(cleared_ci.label));
 | 
				
			||||||
 | 
						osmo_strlcpy(cleared_ci.mgcp_ci_str, ci->mgcp_ci_str, sizeof(cleared_ci.mgcp_ci_str));
 | 
				
			||||||
 | 
						*ci = cleared_ci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_CI_VERB(ci, LOGL_DEBUG, "notify=%s\n", osmo_fsm_inst_name(ci->notify));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (verb_info)
 | 
				
			||||||
 | 
							ci->verb_info = *verb_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ep->endpoint[0]) {
 | 
				
			||||||
 | 
							if (ci->verb_info.endpoint[0] && strcmp(ci->verb_info.endpoint, ep->endpoint))
 | 
				
			||||||
 | 
								LOG_CI(ci, LOGL_ERROR,
 | 
				
			||||||
 | 
								       "Warning: Requested %s on endpoint %s, but this CI is on endpoint %s."
 | 
				
			||||||
 | 
								       " Using the proper endpoint instead.\n",
 | 
				
			||||||
 | 
								       osmo_mgcp_verb_name(verb), ci->verb_info.endpoint, ep->endpoint);
 | 
				
			||||||
 | 
							osmo_strlcpy(ci->verb_info.endpoint, ep->endpoint, sizeof(ci->verb_info.endpoint));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ci->verb) {
 | 
				
			||||||
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
 | 
							if (ci->mgcp_client_fi) {
 | 
				
			||||||
 | 
								LOG_CI(ci, LOGL_ERROR, "CRCX can be called only once per MGW endpoint CI\n");
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MGCP_VERB_MDCX:
 | 
				
			||||||
 | 
							if (!ci->mgcp_client_fi) {
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_ERROR, "The first verb on an unused MGW endpoint CI must be CRCX, not %s\n",
 | 
				
			||||||
 | 
									    osmo_mgcp_verb_name(ci->verb));
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MGCP_VERB_DLCX:
 | 
				
			||||||
 | 
							if (!ci->mgcp_client_fi) {
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_DEBUG, "Ignoring DLCX on unused MGW endpoint CI\n");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_ERROR, "This verb is not supported: %s\n", osmo_mgcp_verb_name(ci->verb));
 | 
				
			||||||
 | 
							on_failure(ci);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ci->pending = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_CI_VERB(ci, LOGL_DEBUG, "Scheduling\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ep->fi->state != OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)
 | 
				
			||||||
 | 
							osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					dispatch_error:
 | 
				
			||||||
 | 
						if (notify)
 | 
				
			||||||
 | 
							osmo_fsm_inst_dispatch(notify, event_failure, notify_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int send_verb(struct osmo_mgcpc_ep_ci *ci)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = ci->ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ci->occupied || !ci->pending || ci->sent)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ci->verb) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MGCP_VERB_CRCX:
 | 
				
			||||||
 | 
							OSMO_ASSERT(!ci->mgcp_client_fi);
 | 
				
			||||||
 | 
							LOG_CI_VERB(ci, LOGL_DEBUG, "Sending\n");
 | 
				
			||||||
 | 
							ci->mgcp_client_fi = mgcp_conn_create(ep->mgcp_client, ep->fi,
 | 
				
			||||||
 | 
											      CI_EV_FAILURE(ci), CI_EV_SUCCESS(ci),
 | 
				
			||||||
 | 
											      &ci->verb_info);
 | 
				
			||||||
 | 
							ci->sent = true;
 | 
				
			||||||
 | 
							if (!ci->mgcp_client_fi){
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_ERROR, "Cannot send\n");
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							osmo_fsm_inst_update_id(ci->mgcp_client_fi, ci->label);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MGCP_VERB_MDCX:
 | 
				
			||||||
 | 
							OSMO_ASSERT(ci->mgcp_client_fi);
 | 
				
			||||||
 | 
							LOG_CI_VERB(ci, LOGL_DEBUG, "Sending\n");
 | 
				
			||||||
 | 
							rc = mgcp_conn_modify(ci->mgcp_client_fi, CI_EV_SUCCESS(ci), &ci->verb_info);
 | 
				
			||||||
 | 
							ci->sent = true;
 | 
				
			||||||
 | 
							if (rc) {
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_ERROR, "Cannot send (rc=%d %s)\n", rc, strerror(-rc));
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MGCP_VERB_DLCX:
 | 
				
			||||||
 | 
							LOG_CI(ci, LOGL_DEBUG, "Sending MGCP: %s %s\n",
 | 
				
			||||||
 | 
							       osmo_mgcp_verb_name(ci->verb), ci->mgcp_ci_str);
 | 
				
			||||||
 | 
							/* The way this is designed, we actually need to forget all about the ci right away. */
 | 
				
			||||||
 | 
							mgcp_conn_delete(ci->mgcp_client_fi);
 | 
				
			||||||
 | 
							if (ci->notify)
 | 
				
			||||||
 | 
								osmo_fsm_inst_dispatch(ci->notify, ci->notify_success, ci->notify_data);
 | 
				
			||||||
 | 
							*ci = (struct osmo_mgcpc_ep_ci){
 | 
				
			||||||
 | 
								.ep = ep,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! DLCX all connections, terminate the endpoint FSM and free. */
 | 
				
			||||||
 | 
					void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ep)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						osmo_fsm_inst_term(ep->fi, OSMO_FSM_TERM_REGULAR, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmo_mgcpc_ep_count(struct osmo_mgcpc_ep *ep, int *occupied, int *pending_not_sent,
 | 
				
			||||||
 | 
									int *waiting_for_response)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (occupied)
 | 
				
			||||||
 | 
							*occupied = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pending_not_sent)
 | 
				
			||||||
 | 
							*pending_not_sent = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (waiting_for_response)
 | 
				
			||||||
 | 
							*waiting_for_response = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
 | 
				
			||||||
 | 
							struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];
 | 
				
			||||||
 | 
							if (ci->occupied) {
 | 
				
			||||||
 | 
								if (occupied)
 | 
				
			||||||
 | 
									(*occupied)++;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ci->pending)
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_DEBUG, "%s\n",
 | 
				
			||||||
 | 
									    ci->sent ? "waiting for response" : "waiting to be sent");
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								LOG_CI_VERB(ci, LOGL_DEBUG, "done (%s)\n", mgcp_conn_peer_name(osmo_mgcpc_ep_ci_get_rtp_info(ci)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ci->pending && ci->sent)
 | 
				
			||||||
 | 
								if (waiting_for_response)
 | 
				
			||||||
 | 
									(*waiting_for_response)++;
 | 
				
			||||||
 | 
							if (ci->pending && !ci->sent)
 | 
				
			||||||
 | 
								if (pending_not_sent)
 | 
				
			||||||
 | 
									(*pending_not_sent)++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool osmo_mgcpc_ep_fsm_check_state_chg_after_response(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int waiting_for_response;
 | 
				
			||||||
 | 
						int occupied;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_mgcpc_ep_count(ep, &occupied, NULL, &waiting_for_response);
 | 
				
			||||||
 | 
						LOG_MGCPC_EP(ep, LOGL_DEBUG, "CI in use: %d, waiting for response: %d\n", occupied, waiting_for_response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!occupied)  {
 | 
				
			||||||
 | 
							/* All CI have been released. The endpoint no longer exists. Notify the parent FSM, by
 | 
				
			||||||
 | 
							 * terminating. */
 | 
				
			||||||
 | 
							osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!waiting_for_response) {
 | 
				
			||||||
 | 
							if (fi->state != OSMO_MGCPC_EP_ST_IN_USE)
 | 
				
			||||||
 | 
								osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_IN_USE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmo_mgcpc_ep_fsm_wait_mgw_response_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static int re_enter = 0;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int count = 0;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						re_enter++;
 | 
				
			||||||
 | 
						OSMO_ASSERT(re_enter < 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The first CRCX gives us the endpoint name in the CRCX response. So we must wait for the first CRCX endpoint
 | 
				
			||||||
 | 
						 * response to come in before sending any other MGCP requests -- otherwise we might end up creating new
 | 
				
			||||||
 | 
						 * endpoints instead of acting on the same. This FSM always sends out N requests and waits for all of them to
 | 
				
			||||||
 | 
						 * complete before sending out new requests. Hence we're safe when the very first time at most one request is
 | 
				
			||||||
 | 
						 * sent (which needs to be a CRCX). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
 | 
				
			||||||
 | 
							struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Make sure that only CRCX get dispatched if no CRCX were sent yet. */
 | 
				
			||||||
 | 
							if (!ep->first_crcx_complete) {
 | 
				
			||||||
 | 
								if (ci->occupied && ci->verb != MGCP_VERB_CRCX)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = send_verb(&ep->ci[i]);
 | 
				
			||||||
 | 
							/* Need to be careful not to access the instance after failure. Event chains may already have
 | 
				
			||||||
 | 
							 * deallocated this memory. */
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							if (!rc)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							count++;
 | 
				
			||||||
 | 
							/* Make sure that we wait for the first CRCX response before dispatching more requests. */
 | 
				
			||||||
 | 
							if (!ep->first_crcx_complete)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOG_MGCPC_EP(ep, LOGL_DEBUG, "Sent messages: %d\n", count);
 | 
				
			||||||
 | 
						if (ep->first_crcx_complete)
 | 
				
			||||||
 | 
							osmo_mgcpc_ep_fsm_check_state_chg_after_response(fi);
 | 
				
			||||||
 | 
						re_enter--;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmo_mgcpc_ep_fsm_handle_ci_events(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep_ci *ci;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
						ci = osmo_mgcpc_ep_ci_for_event(ep, event);
 | 
				
			||||||
 | 
						if (ci) {
 | 
				
			||||||
 | 
							if (event == CI_EV_SUCCESS(ci))
 | 
				
			||||||
 | 
								on_success(ci, data);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void osmo_mgcpc_ep_fsm_in_use_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int pending_not_sent;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_mgcpc_ep_count(ep, NULL, &pending_not_sent, NULL);
 | 
				
			||||||
 | 
						if (pending_not_sent)
 | 
				
			||||||
 | 
							osmo_mgcpc_ep_fsm_state_chg(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define S(x)	(1 << (x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct osmo_fsm_state osmo_mgcpc_ep_fsm_states[] = {
 | 
				
			||||||
 | 
						[OSMO_MGCPC_EP_ST_UNUSED] = {
 | 
				
			||||||
 | 
							.name = "UNUSED",
 | 
				
			||||||
 | 
							.in_event_mask = 0,
 | 
				
			||||||
 | 
							.out_state_mask = 0
 | 
				
			||||||
 | 
								| S(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)
 | 
				
			||||||
 | 
								,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE] = {
 | 
				
			||||||
 | 
							.name = "WAIT_MGW_RESPONSE",
 | 
				
			||||||
 | 
							.onenter = osmo_mgcpc_ep_fsm_wait_mgw_response_onenter,
 | 
				
			||||||
 | 
							.action = osmo_mgcpc_ep_fsm_handle_ci_events,
 | 
				
			||||||
 | 
							.in_event_mask = 0xffffffff,
 | 
				
			||||||
 | 
							.out_state_mask = 0
 | 
				
			||||||
 | 
								| S(OSMO_MGCPC_EP_ST_IN_USE)
 | 
				
			||||||
 | 
								,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[OSMO_MGCPC_EP_ST_IN_USE] = {
 | 
				
			||||||
 | 
							.name = "IN_USE",
 | 
				
			||||||
 | 
							.onenter = osmo_mgcpc_ep_fsm_in_use_onenter,
 | 
				
			||||||
 | 
							.action = osmo_mgcpc_ep_fsm_handle_ci_events,
 | 
				
			||||||
 | 
							.in_event_mask = 0xffffffff, /* mgcp_client_fsm may send parent term anytime */
 | 
				
			||||||
 | 
							.out_state_mask = 0
 | 
				
			||||||
 | 
								| S(OSMO_MGCPC_EP_ST_WAIT_MGW_RESPONSE)
 | 
				
			||||||
 | 
								,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (fi->T) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							for (i = 0; i < ARRAY_SIZE(ep->ci); i++) {
 | 
				
			||||||
 | 
								struct osmo_mgcpc_ep_ci *ci = &ep->ci[i];
 | 
				
			||||||
 | 
								if (!ci->occupied)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								if (!(ci->pending && ci->sent))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								on_failure(ci);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct osmo_fsm osmo_mgcpc_ep_fsm = {
 | 
				
			||||||
 | 
						.name = "mgw-endp",
 | 
				
			||||||
 | 
						.states = osmo_mgcpc_ep_fsm_states,
 | 
				
			||||||
 | 
						.num_states = ARRAY_SIZE(osmo_mgcpc_ep_fsm_states),
 | 
				
			||||||
 | 
						.log_subsys = DLMGCP,
 | 
				
			||||||
 | 
						.event_names = osmo_mgcpc_ep_fsm_event_names,
 | 
				
			||||||
 | 
						.timer_cb = osmo_mgcpc_ep_fsm_timer_cb,
 | 
				
			||||||
 | 
						/* The FSM termination will automatically trigger any mgcp_client_fsm instances to DLCX. */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -114,16 +114,23 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
 | 
				
			|||||||
		.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
							.conn_mode = MGCP_CONN_RECV_ONLY,
 | 
				
			||||||
		.ptime = info->ptime,
 | 
							.ptime = info->ptime,
 | 
				
			||||||
		.codecs_len = info->codecs_len,
 | 
							.codecs_len = info->codecs_len,
 | 
				
			||||||
		.ptmap_len = info->ptmap_len
 | 
							.ptmap_len = info->ptmap_len,
 | 
				
			||||||
 | 
							.param_present = info->param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
 | 
						memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
 | 
				
			||||||
	memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
						memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
 | 
				
			||||||
 | 
						memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info->x_osmo_ign) {
 | 
						if (info->x_osmo_ign) {
 | 
				
			||||||
		mgcp_msg->x_osmo_ign = info->x_osmo_ign;
 | 
							mgcp_msg->x_osmo_ign = info->x_osmo_ign;
 | 
				
			||||||
		mgcp_msg->presence |= MGCP_MSG_PRESENCE_X_OSMO_IGN;
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_X_OSMO_IGN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->x_osmo_osmux_use) {
 | 
				
			||||||
 | 
							mgcp_msg->x_osmo_osmux_cid = info->x_osmo_osmux_cid;
 | 
				
			||||||
 | 
							mgcp_msg->presence |= MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
					static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
				
			||||||
@@ -134,6 +141,13 @@ static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
 | 
				
			|||||||
	mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
						mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enum mgcp_connection_mode conn_mode = peer->conn_mode;
 | 
				
			||||||
 | 
						if (conn_mode != MGCP_CONN_NONE)
 | 
				
			||||||
 | 
							mgcp_msg->conn_mode = conn_mode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
					static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_msg mgcp_msg;
 | 
						struct mgcp_msg mgcp_msg;
 | 
				
			||||||
@@ -149,11 +163,20 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
 | 
				
			|||||||
		.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
							.audio_port = mgcp_ctx->conn_peer_local.port,
 | 
				
			||||||
		.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
							.ptime = mgcp_ctx->conn_peer_local.ptime,
 | 
				
			||||||
		.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
 | 
							.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
 | 
				
			||||||
		.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len
 | 
							.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
 | 
				
			||||||
 | 
							.param_present = mgcp_ctx->conn_peer_local.param_present
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
						osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
 | 
				
			||||||
	memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
 | 
						memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
 | 
				
			||||||
	memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
						memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
 | 
				
			||||||
 | 
						memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_ctx->conn_peer_local.x_osmo_osmux_use) {
 | 
				
			||||||
 | 
							mgcp_msg.x_osmo_osmux_cid = mgcp_ctx->conn_peer_local.x_osmo_osmux_cid;
 | 
				
			||||||
 | 
							mgcp_msg.presence |= MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: We take the endpoint and the call_id from the remote
 | 
						/* Note: We take the endpoint and the call_id from the remote
 | 
				
			||||||
	 * connection info, because we can be confident that the
 | 
						 * connection info, because we can be confident that the
 | 
				
			||||||
@@ -199,6 +222,8 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
				
			|||||||
		make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
							make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
		if (mgcp_ctx->conn_peer_local.port)
 | 
							if (mgcp_ctx->conn_peer_local.port)
 | 
				
			||||||
			add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
								add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
 | 
							set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
							msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
 | 
				
			||||||
		OSMO_ASSERT(msg);
 | 
							OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -255,6 +280,11 @@ static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
 | 
						LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
 | 
				
			||||||
 | 
						if (r->head.x_osmo_osmux_use) {
 | 
				
			||||||
 | 
							LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded using Osmux %u\n", r->head.x_osmo_osmux_cid);
 | 
				
			||||||
 | 
							mgcp_ctx->conn_peer_remote.x_osmo_osmux_use = true;
 | 
				
			||||||
 | 
							mgcp_ctx->conn_peer_remote.x_osmo_osmux_cid = r->head.x_osmo_osmux_cid;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
 | 
						osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
 | 
				
			||||||
	mgcp_ctx->conn_peer_remote.port = r->audio_port;
 | 
						mgcp_ctx->conn_peer_remote.port = r->audio_port;
 | 
				
			||||||
@@ -374,6 +404,12 @@ static void mgw_mdcx_resp_cb(struct mgcp_response *r, void *priv)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	LOGPFSML(fi, LOGL_DEBUG, "MGW/MDCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
 | 
						LOGPFSML(fi, LOGL_DEBUG, "MGW/MDCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (r->head.x_osmo_osmux_use) {
 | 
				
			||||||
 | 
							LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded using Osmux %u\n", r->head.x_osmo_osmux_cid);
 | 
				
			||||||
 | 
							mgcp_ctx->conn_peer_remote.x_osmo_osmux_use = true;
 | 
				
			||||||
 | 
							mgcp_ctx->conn_peer_remote.x_osmo_osmux_cid = r->head.x_osmo_osmux_cid;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
 | 
						osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
 | 
				
			||||||
	mgcp_ctx->conn_peer_remote.port = r->audio_port;
 | 
						mgcp_ctx->conn_peer_remote.port = r->audio_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -685,3 +721,25 @@ void mgcp_conn_delete(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
 | 
						osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
 | 
				
			||||||
 | 
						 * this buffer is too small. */
 | 
				
			||||||
 | 
						static char buf[1024];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!info)
 | 
				
			||||||
 | 
							return "NULL";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->endpoint[0]
 | 
				
			||||||
 | 
						    && info->addr[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s:%s:%u",
 | 
				
			||||||
 | 
								 info->endpoint, info->addr, info->port);
 | 
				
			||||||
 | 
						else if (info->endpoint[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s", info->endpoint);
 | 
				
			||||||
 | 
						else if (info->addr[0])
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "%s:%u", info->addr, info->port);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return "empty";
 | 
				
			||||||
 | 
						return buf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,4 +40,6 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_conn.c \
 | 
						mgcp_conn.c \
 | 
				
			||||||
	mgcp_stat.c \
 | 
						mgcp_stat.c \
 | 
				
			||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
 | 
						iuup_protocol.c \
 | 
				
			||||||
 | 
						iuup_cn_node.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										211
									
								
								src/libosmo-mgcp/iuup_cn_node.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								src/libosmo-mgcp/iuup_cn_node.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
				
			|||||||
 | 
					/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
 | 
				
			||||||
 | 
					/* IuUP Core Network side protocol handling, minimal implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Neels Hofmeyr <neels@hofmeyr.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <talloc.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/iuup_cn_node.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/iuup_protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOG_IUUP_CN(cn, level, fmt, args...) \
 | 
				
			||||||
 | 
							LOGP(DIUUP, level, "(%s) " fmt, (cn)->name, ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
 | 
				
			||||||
 | 
									       const char *name_fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
						struct osmo_iuup_cn *cn = talloc_zero(ctx, struct osmo_iuup_cn);
 | 
				
			||||||
 | 
						OSMO_ASSERT(cn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cn->cfg = *cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!name_fmt)
 | 
				
			||||||
 | 
							name_fmt = "-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, name_fmt);
 | 
				
			||||||
 | 
						cn->name = talloc_vasprintf(cn, name_fmt, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DIUUP, LOGL_INFO, "(%s) Initializing IuUP node\n", cn->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!osmo_identifier_valid(cn->name)) {
 | 
				
			||||||
 | 
							LOGP(DIUUP, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
 | 
				
			||||||
 | 
							     osmo_quote_str(cn->name, -1));
 | 
				
			||||||
 | 
							talloc_free(cn);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void osmo_iuup_cn_free(struct osmo_iuup_cn *cn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						talloc_free(cn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,
 | 
				
			||||||
 | 
							   struct osmo_iuup_hdr_data *hdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */
 | 
				
			||||||
 | 
						/* And append AMR 12.2k header "0xf03c". - AD HOC fix */
 | 
				
			||||||
 | 
						unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;
 | 
				
			||||||
 | 
						memmove(pdu->data + sizeof(*hdr) - 2, pdu->data, pre_hdr_len);
 | 
				
			||||||
 | 
						((uint8_t*)hdr)[2] = 0xf0;
 | 
				
			||||||
 | 
						((uint8_t*)hdr)[3] = 0x3c;
 | 
				
			||||||
 | 
						msgb_pull(pdu, sizeof(*hdr) - 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP stripping IuUP header from RTP data\n", cn->name);
 | 
				
			||||||
 | 
						cn->cfg.rx_payload(pdu, cn->cfg.node_priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tx_init_ack(struct osmo_iuup_cn *cn, struct msgb *src_pdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Send Initialization Ack PDU back to the sender */
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");
 | 
				
			||||||
 | 
						OSMO_ASSERT(ack);
 | 
				
			||||||
 | 
						ack->dst = src_pdu->dst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Just copy the RTP header that was sent... TODO: tweak some RTP values?? */
 | 
				
			||||||
 | 
						memcpy(msgb_put(ack, sizeof(struct rtp_hdr)), src_pdu->data, sizeof(struct rtp_hdr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_iuup_make_init_ack(ack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DIUUP, LOGL_DEBUG, "(%s) Sending Initialization ACK %p\n", cn->name, cn->cfg.node_priv);
 | 
				
			||||||
 | 
						rc = cn->cfg.tx_msg(ack, cn->cfg.node_priv);
 | 
				
			||||||
 | 
						msgb_free(ack);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,
 | 
				
			||||||
 | 
							      struct osmo_iuup_hdr_ctrl *hdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (hdr->procedure) {
 | 
				
			||||||
 | 
						case OSMO_IUUP_PROC_INITIALIZATION:
 | 
				
			||||||
 | 
							switch (hdr->ack_nack) {
 | 
				
			||||||
 | 
							case OSMO_IUUP_ACKNACK_PROCEDURE:
 | 
				
			||||||
 | 
								LOGP(DIUUP, LOGL_INFO, "(%s) Rx IuUP Initialization, sending ACK\n", cn->name);
 | 
				
			||||||
 | 
								cn->rtp_payload_type = ((struct rtp_hdr*)pdu->data)->payload_type;
 | 
				
			||||||
 | 
								return tx_init_ack(cn, pdu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								LOGP(DIUUP, LOGL_DEBUG, "(%s) Rx IuUP Initialization, unhandled ack_nack = %d\n",
 | 
				
			||||||
 | 
								     cn->name, hdr->ack_nack);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/* Continue to log "unexpected procedure" below. */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_IUUP_PROC_ERROR_EVENT:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								union osmo_iuup_hdr_ctrl_payload *p = (void*)hdr->payload;
 | 
				
			||||||
 | 
								LOGP(DIUUP, LOGL_ERROR,
 | 
				
			||||||
 | 
								     "(%s) Rx IuUP Error Event: distance=%u, cause=%u=\"%s\"\n",
 | 
				
			||||||
 | 
								     cn->name, p->error_event.error_distance, p->error_event.error_cause,
 | 
				
			||||||
 | 
								     osmo_iuup_error_cause_name(p->error_event.error_cause));
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						LOG_IUUP_CN(cn, LOGL_ERROR,
 | 
				
			||||||
 | 
							    "Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
 | 
				
			||||||
 | 
							    hdr->procedure, hdr->ack_nack);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Feed a received PDU to the IuUP CN node. This function takes ownership of the msgb, it must not be
 | 
				
			||||||
 | 
					 * freed by the caller. */
 | 
				
			||||||
 | 
					int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_iuup_hdr_ctrl *is_ctrl;
 | 
				
			||||||
 | 
						struct osmo_iuup_hdr_data *is_data;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_iuup_classify(true, cn->name, pdu, &is_ctrl, &is_data);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_ctrl)
 | 
				
			||||||
 | 
							return rx_control(cn, pdu, is_ctrl);
 | 
				
			||||||
 | 
						if (is_data)
 | 
				
			||||||
 | 
							return rx_data(cn, pdu, is_data);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t frame_nr = cn->next_frame_nr;
 | 
				
			||||||
 | 
						cn->next_frame_nr = (frame_nr + 1) & 0x0f;
 | 
				
			||||||
 | 
						return frame_nr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Send this RTP packet to the IuUP peer: add IuUP header and call the tx_msg() to transmit the resulting
 | 
				
			||||||
 | 
					 * message to the IuUP peer.
 | 
				
			||||||
 | 
					 * Returns 0 on success, negative on error. */
 | 
				
			||||||
 | 
					int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtp_hdr *rtp_was, *rtp;
 | 
				
			||||||
 | 
						struct osmo_iuup_hdr_data *iuup_hdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Splice an IuUP header in between RTP header and payload data */
 | 
				
			||||||
 | 
						rtp_was = (void*)pdu->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy the RTP header part backwards by the size needed for the IuUP header */
 | 
				
			||||||
 | 
						/* also strips 2 bytes from the front of RTP payload - AMR header - AD HOC fix */
 | 
				
			||||||
 | 
						rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr) - 2);
 | 
				
			||||||
 | 
						memmove(rtp, rtp_was, sizeof(*rtp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The IuUP side negotiated a payload type number to use during Initialization. The RTP packet going to the IuUP
 | 
				
			||||||
 | 
						 * peer should reflect this payload_type. This should already have happened in mgcp_patch_pt(), but can't hurt
 | 
				
			||||||
 | 
						 * to patch over it again. */
 | 
				
			||||||
 | 
						rtp->payload_type = cn->rtp_payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iuup_hdr = (void*)rtp->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*iuup_hdr = (struct osmo_iuup_hdr_data){
 | 
				
			||||||
 | 
							.pdu_type = OSMO_IUUP_PDU_DATA_WITH_CRC,
 | 
				
			||||||
 | 
							.frame_nr = next_frame_nr(cn),
 | 
				
			||||||
 | 
							.frame_good = OSMO_IUUP_FRAME_GOOD,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);
 | 
				
			||||||
 | 
						LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP inserting IuUP header in RTP data (frame nr %u)\n",
 | 
				
			||||||
 | 
						     cn->name, iuup_hdr->frame_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cn->cfg.tx_msg(pdu, cn->cfg.node_priv);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										286
									
								
								src/libosmo-mgcp/iuup_protocol.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								src/libosmo-mgcp/iuup_protocol.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,286 @@
 | 
				
			|||||||
 | 
					/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
 | 
				
			||||||
 | 
					/* IuUP Core Network side protocol, minimal implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Author: Neels Hofmeyr <neels@hofmeyr.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/iuup_protocol.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Calculating two bytes of CRC is ok to do by a loop */
 | 
				
			||||||
 | 
					static uint8_t header_crc6(const uint8_t *hdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int bit;
 | 
				
			||||||
 | 
					    /* Polynomial: D^6 + D^5 + D^3 + D^2 + D^1 + 1
 | 
				
			||||||
 | 
					     * that's 1101111 or 0x6f;
 | 
				
			||||||
 | 
					     * align its lowest bit with a uint16_t's highest bit: */
 | 
				
			||||||
 | 
					    uint32_t polynomial = 0x6f << 15; // 00110111 10000000 00000000
 | 
				
			||||||
 | 
					    uint32_t remainder = ( ((uint32_t)hdr[0]) << 8 | hdr[1] ) << 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (bit = 15; bit >= 0; bit--)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (remainder & (0x40 << bit))
 | 
				
			||||||
 | 
					            remainder ^= polynomial;
 | 
				
			||||||
 | 
					        polynomial >>= 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return remainder;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Charles Michael Heard's CRC-10 code, from
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://web.archive.org/web/20061005231950/http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/crc10.html
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * with the CRC table initialized with values computed by
 | 
				
			||||||
 | 
					 * his "gen_byte_crc10_table()" routine, rather than by calling that
 | 
				
			||||||
 | 
					 * routine at run time, and with various data type cleanups.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static const uint16_t byte_crc10_table[256] = {
 | 
				
			||||||
 | 
						0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff,
 | 
				
			||||||
 | 
						0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe,
 | 
				
			||||||
 | 
						0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce,
 | 
				
			||||||
 | 
						0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf,
 | 
				
			||||||
 | 
						0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d,
 | 
				
			||||||
 | 
						0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c,
 | 
				
			||||||
 | 
						0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac,
 | 
				
			||||||
 | 
						0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad,
 | 
				
			||||||
 | 
						0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b,
 | 
				
			||||||
 | 
						0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a,
 | 
				
			||||||
 | 
						0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a,
 | 
				
			||||||
 | 
						0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b,
 | 
				
			||||||
 | 
						0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259,
 | 
				
			||||||
 | 
						0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158,
 | 
				
			||||||
 | 
						0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268,
 | 
				
			||||||
 | 
						0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169,
 | 
				
			||||||
 | 
						0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377,
 | 
				
			||||||
 | 
						0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076,
 | 
				
			||||||
 | 
						0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346,
 | 
				
			||||||
 | 
						0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047,
 | 
				
			||||||
 | 
						0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315,
 | 
				
			||||||
 | 
						0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014,
 | 
				
			||||||
 | 
						0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324,
 | 
				
			||||||
 | 
						0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025,
 | 
				
			||||||
 | 
						0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3,
 | 
				
			||||||
 | 
						0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2,
 | 
				
			||||||
 | 
						0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382,
 | 
				
			||||||
 | 
						0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083,
 | 
				
			||||||
 | 
						0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1,
 | 
				
			||||||
 | 
						0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0,
 | 
				
			||||||
 | 
						0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0,
 | 
				
			||||||
 | 
						0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t crc10(uint16_t crc10_accum, const uint8_t *payload, unsigned int payload_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < payload_len; i++) {
 | 
				
			||||||
 | 
							crc10_accum = ((crc10_accum << 8) & 0x300)
 | 
				
			||||||
 | 
								^ byte_crc10_table[(crc10_accum >> 2) & 0xff]
 | 
				
			||||||
 | 
								^ payload[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return crc10_accum;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* When a payload of a multiple of bytes has run through, we need to still feed 10 bits of zeros into the
 | 
				
			||||||
 | 
					 * CRC10 to get the payload's checksum result that we can send to a peer. That can't be done with above
 | 
				
			||||||
 | 
					 * table, because it acts as if full 16 bits are fed. This stops after 10 bits. */
 | 
				
			||||||
 | 
					static uint16_t crc10_remainder(uint16_t crc10_accum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int bit;
 | 
				
			||||||
 | 
					    /* Polynomial: D^10 + D^9 + D^5 + D^4 + D^1 + 1
 | 
				
			||||||
 | 
					     * that's 11000110011 or 0x633;
 | 
				
			||||||
 | 
					     * align its lowest bit with a 10bit value's highest bit: */
 | 
				
			||||||
 | 
					    uint32_t polynomial = 0x633 << 9; // 1100 01100110 00000000
 | 
				
			||||||
 | 
					    uint32_t remainder = ((uint32_t)crc10_accum) << 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Run on 10 bits */
 | 
				
			||||||
 | 
					    for (bit = 9; bit >= 0; bit--)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (remainder & ((1 << 10) << bit))
 | 
				
			||||||
 | 
					            remainder ^= polynomial;
 | 
				
			||||||
 | 
					        polynomial >>= 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return remainder & 0x3ff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint16_t payload_crc10(const uint8_t *payload, unsigned int payload_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint16_t crc10_accum = crc10(0, payload, payload_len);
 | 
				
			||||||
 | 
						return crc10_remainder(crc10_accum);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Given an IuUP PDU data block, write the correct header and payload CRC checksums at the right places.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* For both data and ctrl, the checksums and payload are at the same offset */
 | 
				
			||||||
 | 
						struct osmo_iuup_hdr_data *hdr = (void*)iuup_header_and_payload;
 | 
				
			||||||
 | 
						uint16_t crc;
 | 
				
			||||||
 | 
						unsigned int payload_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr->header_crc = header_crc6(iuup_header_and_payload);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						payload_len = iuup_header_and_payload + header_and_payload_len - hdr->payload;
 | 
				
			||||||
 | 
						crc = payload_crc10(hdr->payload, payload_len);
 | 
				
			||||||
 | 
						hdr->payload_crc_hi = (crc >> 8) & 0x3;
 | 
				
			||||||
 | 
						hdr->payload_crc_lo = crc & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Validate minimum message sizes, IuUP PDU type, header- and payload checksums. If it is a Control
 | 
				
			||||||
 | 
					 * Procedure PDU, return the header position in is_ctrl, if it is a Data PDU, return the header position
 | 
				
			||||||
 | 
					 * in is_data. If log_errors is true, log on DIUUP with the given log label for context. Return NULL in
 | 
				
			||||||
 | 
					 * both is_ctrl and is_data, and return a negative error code if the PDU could not be identified as a
 | 
				
			||||||
 | 
					 * valid RTP PDU containing an IuUP part. */
 | 
				
			||||||
 | 
					int osmo_iuup_classify(bool log_errors,
 | 
				
			||||||
 | 
							       const char *log_label,
 | 
				
			||||||
 | 
							       struct msgb *pdu,
 | 
				
			||||||
 | 
							       struct osmo_iuup_hdr_ctrl **is_ctrl,
 | 
				
			||||||
 | 
							       struct osmo_iuup_hdr_data **is_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtp_hdr *rtp = (void*)pdu->data;
 | 
				
			||||||
 | 
						struct osmo_iuup_hdr_ctrl *hdr = (void*)rtp->data;
 | 
				
			||||||
 | 
						unsigned int payload_len;
 | 
				
			||||||
 | 
						uint16_t crc_calculated;
 | 
				
			||||||
 | 
						uint16_t crc_from_peer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ERR(fmt, args...) do { \
 | 
				
			||||||
 | 
								if (log_errors) \
 | 
				
			||||||
 | 
									LOGP(DIUUP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \
 | 
				
			||||||
 | 
								return -EINVAL; \
 | 
				
			||||||
 | 
							} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_ctrl)
 | 
				
			||||||
 | 
							*is_ctrl = NULL;
 | 
				
			||||||
 | 
						if (is_data)
 | 
				
			||||||
 | 
							*is_data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We need at least a header of 4 bytes. The osmo_iuup_hdr_ctrl already includes a byte of
 | 
				
			||||||
 | 
						 * payload, so use osmo_iuup_hdr_data to check the minimum here. */
 | 
				
			||||||
 | 
						if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_data)))
 | 
				
			||||||
 | 
							ERR("IuUP PDU too short: %u\n", pdu->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Let's not validate checksums if the header type isn't sane */
 | 
				
			||||||
 | 
						switch (hdr->pdu_type) {
 | 
				
			||||||
 | 
						case OSMO_IUUP_PDU_DATA_WITH_CRC:
 | 
				
			||||||
 | 
							/* If the caller isn't interested in data PDUs, cut short here. */
 | 
				
			||||||
 | 
							if (!is_data)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
 | 
				
			||||||
 | 
							/* If the caller isn't interested in control PDUs, cut short here. */
 | 
				
			||||||
 | 
							if (!is_ctrl)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_ctrl)))
 | 
				
			||||||
 | 
								ERR("IuUP control PDU too short: %u\n", pdu->len);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* For both data and ctrl, the checksums and payload are at the same offset */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						crc_calculated = header_crc6((uint8_t*)hdr);
 | 
				
			||||||
 | 
						if (crc_calculated != hdr->header_crc)
 | 
				
			||||||
 | 
							ERR("IuUP PDU with invalid header CRC (peer sent 0x%x, calculated 0x%x)\n",
 | 
				
			||||||
 | 
							    hdr->header_crc, crc_calculated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						payload_len = pdu->tail - hdr->payload;
 | 
				
			||||||
 | 
						crc_calculated = payload_crc10(hdr->payload, payload_len);
 | 
				
			||||||
 | 
						crc_from_peer = (((uint16_t)hdr->payload_crc_hi) << 8) | hdr->payload_crc_lo;
 | 
				
			||||||
 | 
						if (crc_from_peer != crc_calculated)
 | 
				
			||||||
 | 
							ERR("IuUP PDU with invalid payload CRC (peer sent 0x%x, calculated 0x%x)\n",
 | 
				
			||||||
 | 
							    crc_from_peer, crc_calculated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (hdr->pdu_type) {
 | 
				
			||||||
 | 
						case OSMO_IUUP_PDU_DATA_WITH_CRC:
 | 
				
			||||||
 | 
							if (is_data)
 | 
				
			||||||
 | 
								*is_data = (void*)hdr;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
 | 
				
			||||||
 | 
							if (is_ctrl)
 | 
				
			||||||
 | 
								*is_ctrl = hdr;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#undef ERR
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if this RTP packet contains an IuUP Initialization header (detect IuUP peer). */
 | 
				
			||||||
 | 
					bool osmo_iuup_is_init(struct msgb *pdu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					 	struct osmo_iuup_hdr_ctrl *is_ctrl;
 | 
				
			||||||
 | 
						osmo_iuup_classify(false, NULL, pdu, &is_ctrl, NULL);
 | 
				
			||||||
 | 
						return is_ctrl
 | 
				
			||||||
 | 
							&& is_ctrl->procedure == OSMO_IUUP_PROC_INITIALIZATION
 | 
				
			||||||
 | 
							&& is_ctrl->ack_nack == OSMO_IUUP_ACKNACK_PROCEDURE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Append an IuUP Initialization ACK message */
 | 
				
			||||||
 | 
					void osmo_iuup_make_init_ack(struct msgb *ack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Send Initialization Ack PDU back to the sender */
 | 
				
			||||||
 | 
					 	struct osmo_iuup_hdr_ctrl *hdr;
 | 
				
			||||||
 | 
						OSMO_ASSERT(ack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hdr = (void*)msgb_put(ack, sizeof(*hdr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*hdr = (struct osmo_iuup_hdr_ctrl){
 | 
				
			||||||
 | 
							.pdu_type = OSMO_IUUP_PDU_CONTROL_PROCEDURE,
 | 
				
			||||||
 | 
							.ack_nack = OSMO_IUUP_ACKNACK_ACK,
 | 
				
			||||||
 | 
							.procedure = OSMO_IUUP_PROC_INITIALIZATION,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_iuup_set_checksums((uint8_t*)hdr, sizeof(*hdr));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct value_string osmo_iuup_error_cause_names[] = {
 | 
				
			||||||
 | 
						{ 0, "CRC error of frame header" },
 | 
				
			||||||
 | 
						{ 1, "CRC error of frame payload" },
 | 
				
			||||||
 | 
						{ 2, "Unexpected frame number" },
 | 
				
			||||||
 | 
						{ 3, "Frame loss" },
 | 
				
			||||||
 | 
						{ 4, "PDU type unknown" },
 | 
				
			||||||
 | 
						{ 5, "Unknown procedure" },
 | 
				
			||||||
 | 
						{ 6, "Unknown reserved value" },
 | 
				
			||||||
 | 
						{ 7, "Unknown field" },
 | 
				
			||||||
 | 
						{ 8, "Frame too short" },
 | 
				
			||||||
 | 
						{ 9, "Missing fields" },
 | 
				
			||||||
 | 
						{ 16, "Unexpected PDU type" },
 | 
				
			||||||
 | 
						{ 17, "spare" },
 | 
				
			||||||
 | 
						{ 18, "Unexpected procedure" },
 | 
				
			||||||
 | 
						{ 19, "Unexpected RFCI" },
 | 
				
			||||||
 | 
						{ 20, "Unexpected value" },
 | 
				
			||||||
 | 
						{ 42, "Initialisation failure" },
 | 
				
			||||||
 | 
						{ 43, "Initialisation failure (network error, timer expiry)" },
 | 
				
			||||||
 | 
						{ 44, "Initialisation failure (Iu UP function error, repeated NACK)" },
 | 
				
			||||||
 | 
						{ 45, "Rate control failure" },
 | 
				
			||||||
 | 
						{ 46, "Error event failure" },
 | 
				
			||||||
 | 
						{ 47, "Time Alignment not supported" },
 | 
				
			||||||
 | 
						{ 48, "Requested Time Alignment not possible" },
 | 
				
			||||||
 | 
						{ 49, "Iu UP Mode version not supported" },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -56,7 +56,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	endp = conn->conn->endp;
 | 
						endp = conn->conn->endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rtp->codecs_assigned == 0) {
 | 
						if (rtp->codecs_assigned == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x conn:%s no codecs available\n", ENDPOINT_NUMBER(endp),
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn));
 | 
								 mgcp_conn_dump(conn->conn));
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -65,7 +65,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
						for (i = 0; i < rtp->codecs_assigned; i++) {
 | 
				
			||||||
		codec = &rtp->codecs[i];
 | 
							codec = &rtp->codecs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x conn:%s codecs[%u]:%s", ENDPOINT_NUMBER(endp),
 | 
							LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn), i, dump_codec(codec));
 | 
								 mgcp_conn_dump(conn->conn), i, dump_codec(codec));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (codec == rtp->codec)
 | 
							if (codec == rtp->codec)
 | 
				
			||||||
@@ -76,36 +76,61 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initalize or reset codec information with default data. */
 | 
					/* Initalize or reset codec information with default data. */
 | 
				
			||||||
void codec_init(struct mgcp_rtp_codec *codec)
 | 
					static void codec_init(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*codec = (struct mgcp_rtp_codec){
 | 
				
			||||||
 | 
							.payload_type = -1,
 | 
				
			||||||
 | 
							.frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM,
 | 
				
			||||||
 | 
							.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN,
 | 
				
			||||||
 | 
							.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE,
 | 
				
			||||||
 | 
							.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void codec_free(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (codec->subtype_name)
 | 
						if (codec->subtype_name)
 | 
				
			||||||
		talloc_free(codec->subtype_name);
 | 
							talloc_free(codec->subtype_name);
 | 
				
			||||||
	if (codec->audio_name)
 | 
						if (codec->audio_name)
 | 
				
			||||||
		talloc_free(codec->audio_name);
 | 
							talloc_free(codec->audio_name);
 | 
				
			||||||
	memset(codec, 0, sizeof(*codec));
 | 
						*codec = (struct mgcp_rtp_codec){};
 | 
				
			||||||
	codec->payload_type = -1;
 | 
					 | 
				
			||||||
	codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
 | 
					 | 
				
			||||||
	codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
 | 
					 | 
				
			||||||
	codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
 | 
					 | 
				
			||||||
	codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Initalize or reset codec information with default data.
 | 
					/*! Initalize or reset codec information with default data.
 | 
				
			||||||
 *  \param[out] conn related rtp-connection. */
 | 
					 *  \param[out] conn related rtp-connection. */
 | 
				
			||||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
					void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	memset(conn->end.codecs, 0, sizeof(conn->end.codecs));
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < conn->end.codecs_assigned; i++)
 | 
				
			||||||
 | 
							codec_free(&conn->end.codecs[i]);
 | 
				
			||||||
	conn->end.codecs_assigned = 0;
 | 
						conn->end.codecs_assigned = 0;
 | 
				
			||||||
	conn->end.codec = NULL;
 | 
						conn->end.codec = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Set members of struct mgcp_rtp_codec, extrapolate in missing information */
 | 
					/*! Add codec configuration depending on payload type and/or codec name. This
 | 
				
			||||||
static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
					 *  function uses the input parameters to extrapolate the full codec information.
 | 
				
			||||||
		     int payload_type, const char *audio_name, unsigned int pt_offset)
 | 
					 *  \param[out] codec configuration (caller provided memory).
 | 
				
			||||||
 | 
					 *  \param[out] conn related rtp-connection.
 | 
				
			||||||
 | 
					 *  \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
 | 
				
			||||||
 | 
					 *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
 | 
				
			||||||
 | 
					 *  \param[in] param optional codec parameters (set to NULL when unused).
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -EINVAL on failure. */
 | 
				
			||||||
 | 
					int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rate;
 | 
						int rate;
 | 
				
			||||||
	int channels;
 | 
						int channels;
 | 
				
			||||||
	char audio_codec[64];
 | 
						char audio_codec[64];
 | 
				
			||||||
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
 | 
						unsigned int pt_offset = conn->end.codecs_assigned;
 | 
				
			||||||
 | 
						void *ctx = conn->conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The amount of codecs we can store is limited, make sure we do not
 | 
				
			||||||
 | 
						 * overrun this limit. */
 | 
				
			||||||
 | 
						if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First unused entry */
 | 
				
			||||||
 | 
						codec = &conn->end.codecs[conn->end.codecs_assigned];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Initalize the codec struct with some default data to begin with */
 | 
						/* Initalize the codec struct with some default data to begin with */
 | 
				
			||||||
	codec_init(codec);
 | 
						codec_init(codec);
 | 
				
			||||||
@@ -113,12 +138,13 @@ static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			|||||||
	if (payload_type != PTYPE_UNDEFINED) {
 | 
						if (payload_type != PTYPE_UNDEFINED) {
 | 
				
			||||||
		/* Make sure we do not get any reserved or undefined type numbers */
 | 
							/* Make sure we do not get any reserved or undefined type numbers */
 | 
				
			||||||
		/* See also: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
 | 
							/* See also: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
 | 
				
			||||||
		if (payload_type == 1 || payload_type == 2 || payload_type == 19)
 | 
							if ((payload_type == 1 || payload_type == 2 || payload_type == 19)
 | 
				
			||||||
			goto error;
 | 
							    || (payload_type >= 72 && payload_type <= 76)
 | 
				
			||||||
		if (payload_type >= 72 && payload_type <= 76)
 | 
							    || (payload_type >= 127)) {
 | 
				
			||||||
			goto error;
 | 
								LOGP(DLMGCP, LOGL_ERROR, "Cannot add codec, payload type number %d is reserved\n",
 | 
				
			||||||
		if (payload_type >= 127)
 | 
								     payload_type);
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		codec->payload_type = payload_type;
 | 
							codec->payload_type = payload_type;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -144,6 +170,8 @@ static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			|||||||
			/* The given payload type is not known to us, or it
 | 
								/* The given payload type is not known to us, or it
 | 
				
			||||||
			 * it is a dynamic payload type for which we do not
 | 
								 * it is a dynamic payload type for which we do not
 | 
				
			||||||
			 * know the audio name. We must give up here */
 | 
								 * know the audio name. We must give up here */
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_ERROR, "No audio codec name given, and payload type %d unknown\n",
 | 
				
			||||||
 | 
								     payload_type);
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -151,16 +179,23 @@ static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			|||||||
	/* Now we extract the codec subtype name, rate and channels. The latter
 | 
						/* Now we extract the codec subtype name, rate and channels. The latter
 | 
				
			||||||
	 * two are optional. If they are not present we use the safe defaults
 | 
						 * two are optional. If they are not present we use the safe defaults
 | 
				
			||||||
	 * above. */
 | 
						 * above. */
 | 
				
			||||||
	if (strlen(audio_name) > sizeof(audio_codec))
 | 
						if (strlen(audio_name) > sizeof(audio_codec)) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
 | 
						channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
 | 
				
			||||||
	rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
 | 
						rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
 | 
				
			||||||
	if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1)
 | 
						if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: We only accept configurations with one audio channel! */
 | 
						/* Note: We only accept configurations with one audio channel! */
 | 
				
			||||||
	if (channels != 1)
 | 
						if (channels != 1) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Cannot handle audio codec with more than one channel: %s\n",
 | 
				
			||||||
 | 
							     osmo_quote_str(audio_name, -1));
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	codec->rate = rate;
 | 
						codec->rate = rate;
 | 
				
			||||||
	codec->channels = channels;
 | 
						codec->channels = channels;
 | 
				
			||||||
@@ -178,6 +213,7 @@ static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Derive the payload type if it is unknown */
 | 
						/* Derive the payload type if it is unknown */
 | 
				
			||||||
	if (codec->payload_type == PTYPE_UNDEFINED) {
 | 
						if (codec->payload_type == PTYPE_UNDEFINED) {
 | 
				
			||||||
 | 
							/* TODO: This is semi dead code, see OS#4150 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* For the known codecs from the static range we restore
 | 
							/* For the known codecs from the static range we restore
 | 
				
			||||||
		 * the IANA or 3GPP assigned payload type number */
 | 
							 * the IANA or 3GPP assigned payload type number */
 | 
				
			||||||
@@ -213,46 +249,32 @@ static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
 | 
				
			|||||||
		 * 110 onwards 3gpp defines prefered codec types, which are
 | 
							 * 110 onwards 3gpp defines prefered codec types, which are
 | 
				
			||||||
		 * also fixed, see above)  */
 | 
							 * also fixed, see above)  */
 | 
				
			||||||
		if (codec->payload_type < 0) {
 | 
							if (codec->payload_type < 0) {
 | 
				
			||||||
 | 
								/* FIXME: pt_offset is completely unrelated and useless here, any of those numbers may already
 | 
				
			||||||
 | 
								 * have been added to the codecs. Instead, there should be an iterator checking for an actually
 | 
				
			||||||
 | 
								 * unused dynamic payload type number. */
 | 
				
			||||||
			codec->payload_type = 96 + pt_offset;
 | 
								codec->payload_type = 96 + pt_offset;
 | 
				
			||||||
			if (codec->payload_type > 109)
 | 
								if (codec->payload_type > 109) {
 | 
				
			||||||
 | 
									LOGP(DLMGCP, LOGL_ERROR, "Ran out of payload type numbers to assign dynamically\n");
 | 
				
			||||||
				goto error;
 | 
									goto error;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Copy over optional codec parameters */
 | 
				
			||||||
 | 
						if (param) {
 | 
				
			||||||
 | 
							codec->param = *param;
 | 
				
			||||||
 | 
							codec->param_present = true;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							codec->param_present = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn->end.codecs_assigned++;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	/* Make sure we leave a clean codec entry on error. */
 | 
						/* Make sure we leave a clean codec entry on error. */
 | 
				
			||||||
	codec_init(codec);
 | 
						codec_free(codec);
 | 
				
			||||||
	memset(codec, 0, sizeof(*codec));
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Add codec configuration depending on payload type and/or codec name. This
 | 
					 | 
				
			||||||
 *  function uses the input parameters to extrapolate the full codec information.
 | 
					 | 
				
			||||||
 *  \param[out] codec configuration (caller provided memory).
 | 
					 | 
				
			||||||
 *  \param[out] conn related rtp-connection.
 | 
					 | 
				
			||||||
 *  \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
 | 
					 | 
				
			||||||
 *  \param[in] audio_name audio codec name (e.g. "GSM/8000/1").
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on failure. */
 | 
					 | 
				
			||||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The amount of codecs we can store is limited, make sure we do not
 | 
					 | 
				
			||||||
	 * overrun this limit. */
 | 
					 | 
				
			||||||
	if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = codec_set(conn->conn, &conn->end.codecs[conn->end.codecs_assigned], payload_type, audio_name,
 | 
					 | 
				
			||||||
		       conn->end.codecs_assigned);
 | 
					 | 
				
			||||||
	if (rc != 0)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn->end.codecs_assigned++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Check if the given codec is applicable on the specified endpoint
 | 
					/* Check if the given codec is applicable on the specified endpoint
 | 
				
			||||||
 * Helper function for mgcp_codec_decide() */
 | 
					 * Helper function for mgcp_codec_decide() */
 | 
				
			||||||
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
					static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
@@ -342,9 +364,28 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
 | 
					 * Media Type Registration":
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    octet-align: Permissible values are 0 and 1.  If 1, octet-aligned
 | 
				
			||||||
 | 
					 *                 operation SHALL be used.  If 0 or if not present,
 | 
				
			||||||
 | 
					 *                 bandwidth-efficient operation is employed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * https://tools.ietf.org/html/rfc4867
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!codec->param_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (!codec->param.amr_octet_aligned_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return codec->param.amr_octet_aligned;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare two codecs, all parameters must match up, except for the payload type
 | 
					/* Compare two codecs, all parameters must match up, except for the payload type
 | 
				
			||||||
 * number. */
 | 
					 * number. */
 | 
				
			||||||
static bool codecs_cmp(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
					static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (codec_a->rate != codec_b->rate)
 | 
						if (codec_a->rate != codec_b->rate)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -354,10 +395,12 @@ static bool codecs_cmp(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *co
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
						if (codec_a->frame_duration_den != codec_b->frame_duration_den)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (strcmp(codec_a->audio_name, codec_b->audio_name))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
						if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
						if (!strcmp(codec_a->subtype_name, "AMR")) {
 | 
				
			||||||
 | 
							if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -398,7 +441,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
	codecs_assigned = rtp_dst->codecs_assigned;
 | 
						codecs_assigned = rtp_dst->codecs_assigned;
 | 
				
			||||||
	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
						OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
 | 
				
			||||||
	for (i = 0; i < codecs_assigned; i++) {
 | 
						for (i = 0; i < codecs_assigned; i++) {
 | 
				
			||||||
		if (codecs_cmp(codec_src, &rtp_dst->codecs[i])) {
 | 
							if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
 | 
				
			||||||
			codec_dst = &rtp_dst->codecs[i];
 | 
								codec_dst = &rtp_dst->codecs[i];
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -408,3 +451,19 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return codec_dst->payload_type;
 | 
						return codec_dst->payload_type;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
 | 
													const char *subtype_name, unsigned int match_nr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < conn->end.codecs_assigned; i++) {
 | 
				
			||||||
 | 
							if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
 | 
				
			||||||
 | 
								if (match_nr) {
 | 
				
			||||||
 | 
									match_nr--;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return &conn->end.codecs[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/gsm/gsm_utils.h>
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
				
			||||||
@@ -74,14 +75,13 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x, unable to generate a unique connectionIdentifier\n",
 | 
						LOGPENDP(endp, DLMGCP, LOGL_ERROR, "unable to generate a unique connectionIdentifier\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initialize rtp connection struct with default values */
 | 
					/* Initialize rtp connection struct with default values */
 | 
				
			||||||
static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
					static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
						struct mgcp_rtp_end *end = &conn_rtp->end;
 | 
				
			||||||
	/* FIXME: Each new rate counter group requires an unique index. At the
 | 
						/* FIXME: Each new rate counter group requires an unique index. At the
 | 
				
			||||||
@@ -90,7 +90,8 @@ static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn
 | 
				
			|||||||
	static unsigned int rate_ctr_index = 0;
 | 
						static unsigned int rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
						conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
				
			||||||
	conn_rtp->osmux.allocated_cid = -1;
 | 
						conn_rtp->osmux.cid_allocated = false;
 | 
				
			||||||
 | 
						conn_rtp->osmux.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;
 | 
				
			||||||
@@ -108,21 +109,44 @@ static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn
 | 
				
			|||||||
	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->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);
 | 
				
			||||||
 | 
						if (!conn_rtp->rate_ctr_group)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];
 | 
						conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];
 | 
				
			||||||
	conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];
 | 
						conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];
 | 
				
			||||||
	rate_ctr_index++;
 | 
						rate_ctr_index++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Cleanup rtp connection struct */
 | 
					/* Cleanup rtp connection struct */
 | 
				
			||||||
static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
					static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmux_disable_conn(conn_rtp);
 | 
						if (mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
				
			||||||
	osmux_release_cid(conn_rtp);
 | 
							conn_osmux_disable(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->rate_ctr_group);
 | 
				
			||||||
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_conn_watchdog_cb(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_conn *conn = data;
 | 
				
			||||||
 | 
						LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
 | 
				
			||||||
 | 
						mgcp_conn_free(conn->endp, conn->id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int timeout = conn->endp->cfg->conn_timeout;
 | 
				
			||||||
 | 
						if (!timeout)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "watchdog kicked\n");
 | 
				
			||||||
 | 
						osmo_timer_schedule(&conn->watchdog, timeout, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate a new connection list entry.
 | 
					/*! allocate a new connection list entry.
 | 
				
			||||||
@@ -158,7 +182,10 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (type) {
 | 
						switch (type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		mgcp_rtp_conn_init(&conn->u.rtp, conn);
 | 
							if (mgcp_rtp_conn_init(&conn->u.rtp, conn) < 0) {
 | 
				
			||||||
 | 
								talloc_free(conn);
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* NOTE: This should never be called with an
 | 
							/* NOTE: This should never be called with an
 | 
				
			||||||
@@ -167,6 +194,9 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			|||||||
		OSMO_ASSERT(false);
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Initialize watchdog */
 | 
				
			||||||
 | 
						osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
 | 
				
			||||||
 | 
						mgcp_conn_watchdog_kick(conn);
 | 
				
			||||||
	llist_add(&conn->entry, &endp->conns);
 | 
						llist_add(&conn->entry, &endp->conns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return conn;
 | 
						return conn;
 | 
				
			||||||
@@ -274,6 +304,7 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
 | 
				
			|||||||
		OSMO_ASSERT(false);
 | 
							OSMO_ASSERT(false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_timer_del(&conn->watchdog);
 | 
				
			||||||
	llist_del(&conn->entry);
 | 
						llist_del(&conn->entry);
 | 
				
			||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,8 +36,7 @@ const struct mgcp_endpoint_typeset ep_typeset = {
 | 
				
			|||||||
 *  \param[in] endp endpoint to release */
 | 
					 *  \param[in] endp endpoint to release */
 | 
				
			||||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
					void mgcp_endp_release(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint:0x%x\n",
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Normally this function should only be called when
 | 
						/* Normally this function should only be called when
 | 
				
			||||||
	 * all connections have been removed already. In case
 | 
						 * all connections have been removed already. In case
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,9 +82,8 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mode) {
 | 
						if (!mode) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x missing connection mode\n",
 | 
								 "missing connection mode\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!conn)
 | 
						if (!conn)
 | 
				
			||||||
@@ -92,18 +91,17 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
	if (!endp)
 | 
						if (!endp)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(mode, "recvonly") == 0)
 | 
						if (strcasecmp(mode, "recvonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_ONLY;
 | 
							conn->mode = MGCP_CONN_RECV_ONLY;
 | 
				
			||||||
	else if (strcmp(mode, "sendrecv") == 0)
 | 
						else if (strcasecmp(mode, "sendrecv") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_RECV_SEND;
 | 
							conn->mode = MGCP_CONN_RECV_SEND;
 | 
				
			||||||
	else if (strcmp(mode, "sendonly") == 0)
 | 
						else if (strcasecmp(mode, "sendonly") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_SEND_ONLY;
 | 
							conn->mode = MGCP_CONN_SEND_ONLY;
 | 
				
			||||||
	else if (strcmp(mode, "loopback") == 0)
 | 
						else if (strcasecmp(mode, "loopback") == 0)
 | 
				
			||||||
		conn->mode = MGCP_CONN_LOOPBACK;
 | 
							conn->mode = MGCP_CONN_LOOPBACK;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x unknown connection mode: '%s'\n",
 | 
								 "unknown connection mode: '%s'\n", mode);
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp), mode);
 | 
					 | 
				
			||||||
		ret = -1;
 | 
							ret = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,18 +111,15 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
		    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
							    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
				
			||||||
	     "endpoint:0x%x conn:%s\n",
 | 
					 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
 | 
				
			||||||
	     "endpoint:0x%x connection mode '%s' %d\n",
 | 
							 mode, conn->mode);
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), mode, conn->mode);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Special handling für RTP connections */
 | 
						/* Special handling für RTP connections */
 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x output_enabled %d\n",
 | 
							LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp), conn->u.rtp.end.output_enabled);
 | 
								 conn->u.rtp.end.output_enabled);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The VTY might change the connection mode at any time, so we have
 | 
						/* The VTY might change the connection mode at any time, so we have
 | 
				
			||||||
@@ -197,9 +192,8 @@ static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
 | 
				
			|||||||
	for (i = 0; i < number_endpoints; i++) {
 | 
						for (i = 0; i < number_endpoints; i++) {
 | 
				
			||||||
		if (endpoints[i].callid == NULL) {
 | 
							if (endpoints[i].callid == NULL) {
 | 
				
			||||||
			endp = &endpoints[i];
 | 
								endp = &endpoints[i];
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_DEBUG,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
			     "endpoint:0x%x found free endpoint\n",
 | 
								     "found free endpoint\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			endp->wildcarded_req = true;
 | 
								endp->wildcarded_req = true;
 | 
				
			||||||
			return endp;
 | 
								return endp;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -331,7 +325,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 2:
 | 
							case 2:
 | 
				
			||||||
			if (strcmp("MGCP", elem)) {
 | 
								if (strcasecmp("MGCP", elem)) {
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR,
 | 
									LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				     "MGCP header parsing error\n");
 | 
									     "MGCP header parsing error\n");
 | 
				
			||||||
				return -510;
 | 
									return -510;
 | 
				
			||||||
@@ -360,18 +354,27 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
					/*! Extract OSMUX CID from an MGCP parameter line (string).
 | 
				
			||||||
 *  \param[in] line single parameter line from the MGCP message
 | 
					 *  \param[in] line single parameter line from the MGCP message
 | 
				
			||||||
 *  \returns OSMUX CID, -1 on error */
 | 
					 *  \returns OSMUX CID, -1 wildcard, -2 on error */
 | 
				
			||||||
int mgcp_parse_osmux_cid(const char *line)
 | 
					int mgcp_parse_osmux_cid(const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int osmux_cid;
 | 
						int osmux_cid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
 | 
					
 | 
				
			||||||
 | 
						if (strcasecmp(line + 2, "Osmux: *") == 0) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
 | 
				
			||||||
 | 
							     line);
 | 
				
			||||||
 | 
							return -2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmux_cid > OSMUX_CID_MAX) {
 | 
						if (osmux_cid > OSMUX_CID_MAX) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
 | 
				
			||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -1;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -419,9 +422,9 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
 | 
				
			|||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(endp->callid, callid) != 0) {
 | 
						if (strcmp(endp->callid, callid) != 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x CallIDs mismatch: '%s' != '%s'\n",
 | 
								 "CallIDs mismatch: '%s' != '%s'\n",
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp), endp->callid, callid);
 | 
								 endp->callid, callid);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -440,25 +443,23 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Check for null identifiers */
 | 
						/* Check for null identifiers */
 | 
				
			||||||
	if (!conn_id) {
 | 
						if (!conn_id) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x invalid ConnectionIdentifier (missing)\n",
 | 
								 "invalid ConnectionIdentifier (missing)\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		return 510;
 | 
							return 510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check for empty connection identifiers */
 | 
						/* Check for empty connection identifiers */
 | 
				
			||||||
	if (strlen(conn_id) == 0) {
 | 
						if (strlen(conn_id) == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x invalid ConnectionIdentifier (empty)\n",
 | 
								 "invalid ConnectionIdentifier (empty)\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		return 510;
 | 
							return 510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check for over long connection identifiers */
 | 
						/* Check for over long connection identifiers */
 | 
				
			||||||
	if (strlen(conn_id) > (MGCP_CONN_ID_MAXLEN-1)) {
 | 
						if (strlen(conn_id) > (MGCP_CONN_ID_MAXLEN-1)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "endpoint:0x%x invalid ConnectionIdentifier (too long: %zu > %d) 0x%s\n",
 | 
								"invalid ConnectionIdentifier (too long: %zu > %d) 0x%s\n",
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp), strlen(conn_id), MGCP_CONN_ID_MAXLEN-1, conn_id);
 | 
								 strlen(conn_id), MGCP_CONN_ID_MAXLEN-1, conn_id);
 | 
				
			||||||
		return 510;
 | 
							return 510;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -466,9 +467,8 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
 | 
				
			|||||||
	if (mgcp_conn_get(endp, conn_id))
 | 
						if (mgcp_conn_get(endp, conn_id))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
	     "endpoint:0x%x no connection found under ConnectionIdentifier 0x%s\n",
 | 
						     "no connection found under ConnectionIdentifier 0x%s\n", conn_id);
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), conn_id);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* When the conn_id was not found, return error code 515 "The transaction refers to an incorrect
 | 
						/* When the conn_id was not found, return error code 515 "The transaction refers to an incorrect
 | 
				
			||||||
	 * connection-id (may have been already deleted)." */
 | 
						 * connection-id (may have been already deleted)." */
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -15,10 +15,12 @@
 | 
				
			|||||||
#include <inttypes.h> /* for PRIu64 */
 | 
					#include <inttypes.h> /* for PRIu64 */
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
#include <osmocom/netif/rtp.h>
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					#include <osmocom/netif/amr.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp.h>
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_internal.h>
 | 
					#include <osmocom/mgcp/mgcp_internal.h>
 | 
				
			||||||
@@ -34,7 +36,7 @@ struct osmux_handle {
 | 
				
			|||||||
	struct llist_head head;
 | 
						struct llist_head head;
 | 
				
			||||||
	struct osmux_in_handle *in;
 | 
						struct osmux_in_handle *in;
 | 
				
			||||||
	struct in_addr rem_addr;
 | 
						struct in_addr rem_addr;
 | 
				
			||||||
	int rem_port;
 | 
						int rem_port; /* network byte order */
 | 
				
			||||||
	int refcnt;
 | 
						int refcnt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,6 +179,12 @@ int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	memcpy(msg->data, buf, buf_len);
 | 
						memcpy(msg->data, buf, buf_len);
 | 
				
			||||||
	msgb_put(msg, buf_len);
 | 
						msgb_put(msg, buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn->osmux.state != OSMUX_STATE_ENABLED) {
 | 
				
			||||||
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
 | 
				
			||||||
 | 
							conn->osmux.cid);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.cid)) > 0) {
 | 
						while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.cid)) > 0) {
 | 
				
			||||||
		/* batch full, build and deliver it */
 | 
							/* batch full, build and deliver it */
 | 
				
			||||||
		osmux_xfrm_input_deliver(conn->osmux.in);
 | 
							osmux_xfrm_input_deliver(conn->osmux.in);
 | 
				
			||||||
@@ -185,111 +193,49 @@ int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Lookup the endpoint that corresponds to the specified address (port) */
 | 
					/* Lookup the endpoint that corresponds to the specified address (port) */
 | 
				
			||||||
static struct mgcp_endpoint *
 | 
					static struct mgcp_conn_rtp*
 | 
				
			||||||
endpoint_lookup(struct mgcp_config *cfg, int cid,
 | 
					osmux_conn_lookup(struct mgcp_config *cfg, uint8_t cid,
 | 
				
			||||||
		struct in_addr *from_addr, int type)
 | 
							struct in_addr *from_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint *endp = NULL;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
 | 
						struct mgcp_conn *conn = NULL;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp * conn_rtp;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_net = NULL;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_bts = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i=0; i<cfg->trunk.number_endpoints; i++) {
 | 
						for (i=0; i<cfg->trunk.number_endpoints; i++) {
 | 
				
			||||||
		struct in_addr *this;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		endp = &cfg->trunk.endpoints[i];
 | 
							endp = &cfg->trunk.endpoints[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
							llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
		if (!tmp->allocated)
 | 
								if (conn->type != MGCP_CONN_TYPE_RTP)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch(type) {
 | 
								conn_rtp = &conn->u.rtp;
 | 
				
			||||||
		case MGCP_DEST_NET:
 | 
								if (!mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
				
			||||||
			/* FIXME: Get rid of CONN_ID_XXX! */
 | 
									continue;
 | 
				
			||||||
			conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
 | 
					
 | 
				
			||||||
			if (conn_net)
 | 
								if (conn_rtp->osmux.cid == cid)
 | 
				
			||||||
				this = &conn_net->end.addr;
 | 
									return conn_rtp;
 | 
				
			||||||
			else
 | 
							}
 | 
				
			||||||
				this = NULL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case MGCP_DEST_BTS:
 | 
					 | 
				
			||||||
			/* FIXME: Get rid of CONN_ID_XXX! */
 | 
					 | 
				
			||||||
			conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
 | 
					 | 
				
			||||||
			if (conn_bts)
 | 
					 | 
				
			||||||
				this = &conn_bts->end.addr;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				this = NULL;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			/* Should not ever happen */
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
 | 
					 | 
				
			||||||
			return NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* FIXME: Get rid of CONN_ID_XXX! */
 | 
						LOGP(DLMGCP, LOGL_ERROR, "Cannot find osmux conn with cid=%d\n", cid);
 | 
				
			||||||
		conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
 | 
					 | 
				
			||||||
		if (conn_net && this && conn_net->osmux.cid == cid
 | 
					 | 
				
			||||||
		    && this->s_addr == from_addr->s_addr)
 | 
					 | 
				
			||||||
			return endp;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n", cid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void scheduled_tx_net_cb(struct msgb *msg, void *data)
 | 
					/* FIXME: this is declared and used in mgcp_network.c, but documentation of mgcp_dispatch_rtp_bridge_cb() states another enum is to be used */
 | 
				
			||||||
{
 | 
					enum {
 | 
				
			||||||
	struct mgcp_endpoint *endp = data;
 | 
						MGCP_PROTO_RTP,
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_net = NULL;
 | 
						MGCP_PROTO_RTCP,
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_bts = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: Get rid of CONN_ID_XXX! */
 | 
					 | 
				
			||||||
	conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
 | 
					 | 
				
			||||||
	conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
 | 
					 | 
				
			||||||
	if (!conn_bts || !conn_net)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct sockaddr_in addr = {
 | 
					 | 
				
			||||||
		.sin_addr = conn_net->end.addr,
 | 
					 | 
				
			||||||
		.sin_port = conn_net->end.rtp_port,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rate_ctr_inc(&conn_bts->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
 | 
					static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
 | 
				
			||||||
	rate_ctr_add(&conn_bts->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], msg->len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Send RTP data to NET */
 | 
					 | 
				
			||||||
	/* FIXME: Get rid of conn_bts and conn_net! */
 | 
					 | 
				
			||||||
	mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
 | 
					 | 
				
			||||||
		  conn_bts, conn_net);
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint *endp = data;
 | 
						struct mgcp_conn_rtp *conn = data;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_net = NULL;
 | 
						struct mgcp_endpoint *endp = conn->conn->endp;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_bts = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: Get rid of CONN_ID_XXX! */
 | 
						endp->type->dispatch_rtp_cb(msg);
 | 
				
			||||||
	conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
 | 
					 | 
				
			||||||
	conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
 | 
					 | 
				
			||||||
	if (!conn_bts || !conn_net)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct sockaddr_in addr = {
 | 
					 | 
				
			||||||
		.sin_addr = conn_bts->end.addr,
 | 
					 | 
				
			||||||
		.sin_port = conn_bts->end.rtp_port,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rate_ctr_inc(&conn_net->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
 | 
					 | 
				
			||||||
	rate_ctr_add(&conn_net->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], msg->len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Send RTP data to BTS */
 | 
					 | 
				
			||||||
	/* FIXME: Get rid of conn_bts and conn_net! */
 | 
					 | 
				
			||||||
	mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
 | 
					 | 
				
			||||||
		  conn_net, conn_bts);
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -322,21 +268,23 @@ static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_r
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	switch(conn->osmux.state) {
 | 
						switch(conn->osmux.state) {
 | 
				
			||||||
	case OSMUX_STATE_ACTIVATING:
 | 
						case OSMUX_STATE_ACTIVATING:
 | 
				
			||||||
	if (osmux_enable_conn(endp, conn, &conn->end.addr, htons(endp->cfg->osmux_port)) < 0) {
 | 
						if (osmux_enable_conn(endp, conn, &conn->end.addr, conn->end.rtp_port) < 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				"Could not enable osmux for conn:%s\n",
 | 
									 "Could not enable osmux for conn on %s: %s\n",
 | 
				
			||||||
 | 
									 sending ? "sent" : "received",
 | 
				
			||||||
				 mgcp_conn_dump(conn->conn));
 | 
									 mgcp_conn_dump(conn->conn));
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		    "Osmux CID %u for %s:%u is now enabled\n",
 | 
								 "Osmux %s CID %u towards %s:%u is now enabled\n",
 | 
				
			||||||
 | 
								 sending ? "sent" : "received",
 | 
				
			||||||
			 conn->osmux.cid, inet_ntoa(conn->end.addr),
 | 
								 conn->osmux.cid, inet_ntoa(conn->end.addr),
 | 
				
			||||||
		    endp->cfg->osmux_port);
 | 
								 ntohs(conn->end.rtp_port));
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	case OSMUX_STATE_ENABLED:
 | 
						case OSMUX_STATE_ENABLED:
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "Osmux %s in conn %s without full negotiation, state %d\n",
 | 
								 "Osmux %s in conn %s without full negotiation, state %d\n",
 | 
				
			||||||
			 sending ? "sent" : "received",
 | 
								 sending ? "sent" : "received",
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn), conn->osmux.state);
 | 
								 mgcp_conn_dump(conn->conn), conn->osmux.state);
 | 
				
			||||||
@@ -347,9 +295,9 @@ static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_r
 | 
				
			|||||||
static int osmux_legacy_dummy_parse_cid(struct sockaddr_in *addr, struct msgb *msg,
 | 
					static int osmux_legacy_dummy_parse_cid(struct sockaddr_in *addr, struct msgb *msg,
 | 
				
			||||||
					uint8_t *osmux_cid)
 | 
										uint8_t *osmux_cid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (msg->len < 1 + sizeof(osmux_cid)) {
 | 
						if (msg->len < 1 + sizeof(*osmux_cid)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "Discarding truncated Osmux dummy load\n");
 | 
							     "Discarding truncated Osmux dummy load: %s\n", osmo_hexdump(msg->data, msg->len));
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -358,16 +306,40 @@ static int osmux_legacy_dummy_parse_cid(struct sockaddr_in *addr, struct msgb *m
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This is called from the bsc-nat */
 | 
				
			||||||
 | 
					static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
 | 
				
			||||||
 | 
								      struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t osmux_cid;
 | 
				
			||||||
 | 
						struct mgcp_conn_rtp *conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmux_legacy_dummy_parse_cid(addr, msg, &osmux_cid) < 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = osmux_conn_lookup(cfg, osmux_cid, &addr->sin_addr);
 | 
				
			||||||
 | 
						if (!conn) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "Cannot find conn for Osmux CID %d\n", osmux_cid);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp_osmux_state_check(conn->conn->endp, conn, false);
 | 
				
			||||||
 | 
						/* Only needed to punch hole in firewall, it can be dropped */
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define osmux_chunk_length(msg, rem) (rem - msg->len);
 | 
					#define osmux_chunk_length(msg, rem) (rem - msg->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
 | 
					static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
	struct osmux_hdr *osmuxh;
 | 
						struct osmux_hdr *osmuxh;
 | 
				
			||||||
	struct sockaddr_in addr;
 | 
						struct sockaddr_in addr;
 | 
				
			||||||
	struct mgcp_config *cfg = ofd->data;
 | 
						struct mgcp_config *cfg = ofd->data;
 | 
				
			||||||
	uint32_t rem;
 | 
						uint32_t rem;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_bts = NULL;
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = osmux_recv(ofd, &addr);
 | 
						msg = osmux_recv(ofd, &addr);
 | 
				
			||||||
	if (!msg)
 | 
						if (!msg)
 | 
				
			||||||
@@ -381,115 +353,32 @@ int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* not any further processing dummy messages */
 | 
						/* not any further processing dummy messages */
 | 
				
			||||||
	if (msg->data[0] == MGCP_DUMMY_LOAD)
 | 
						if (msg->data[0] == MGCP_DUMMY_LOAD)
 | 
				
			||||||
		goto out;
 | 
							return osmux_handle_dummy(cfg, &addr, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rem = msg->len;
 | 
						rem = msg->len;
 | 
				
			||||||
	while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 | 
						while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 | 
				
			||||||
		struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Yes, we use MGCP_DEST_NET to locate the origin */
 | 
							conn_src = osmux_conn_lookup(cfg, osmuxh->circuit_id,
 | 
				
			||||||
		endp = endpoint_lookup(cfg, osmuxh->circuit_id,
 | 
										     &addr.sin_addr);
 | 
				
			||||||
				       &addr.sin_addr, MGCP_DEST_NET);
 | 
							if (!conn_src) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* FIXME: Get rid of CONN_ID_XXX! */
 | 
					 | 
				
			||||||
		conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
 | 
					 | 
				
			||||||
		if (!conn_bts)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!endp) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "Cannot find an endpoint for circuit_id=%d\n",
 | 
								     "Cannot find a src conn for circuit_id=%d\n",
 | 
				
			||||||
			     osmuxh->circuit_id);
 | 
								     osmuxh->circuit_id);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (endp_osmux_state_check(endp, conn_bts, false) == 0) {
 | 
					 | 
				
			||||||
			conn_bts->osmux.stats.octets += osmux_chunk_length(msg, rem);
 | 
					 | 
				
			||||||
			conn_bts->osmux.stats.chunks++;
 | 
					 | 
				
			||||||
			osmux_xfrm_output_sched(&conn_bts->osmux.out, osmuxh);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rem = msg->len;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is called from the bsc-nat */
 | 
							/*conn_dst = mgcp_find_dst_conn(conn_src->conn);
 | 
				
			||||||
static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
 | 
							if (!conn_dst) {
 | 
				
			||||||
			      struct msgb *msg, int endp_type)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
	uint8_t osmux_cid;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (osmux_legacy_dummy_parse_cid(addr, msg, &osmux_cid) < 0)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endp = endpoint_lookup(cfg, osmux_cid, &addr->sin_addr, endp_type);
 | 
					 | 
				
			||||||
	if (!endp) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "Cannot find endpoint for Osmux CID %d\n", osmux_cid);
 | 
								     "Cannot find a dst conn for circuit_id=%d\n",
 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: Get rid of CONN_ID_XXX! */
 | 
					 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, endp_type == MGCP_DEST_BTS ? CONN_ID_NET : CONN_ID_BTS);
 | 
					 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	endp_osmux_state_check(endp, conn, false);
 | 
					 | 
				
			||||||
	/* Only needed to punch hole in firewall, it can be dropped */
 | 
					 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	struct osmux_hdr *osmuxh;
 | 
					 | 
				
			||||||
	struct sockaddr_in addr;
 | 
					 | 
				
			||||||
	struct mgcp_config *cfg = ofd->data;
 | 
					 | 
				
			||||||
	uint32_t rem;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_net = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg = osmux_recv(ofd, &addr);
 | 
					 | 
				
			||||||
	if (!msg)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!cfg->osmux) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
		     "bsc wants to use Osmux but bsc-nat did not request it\n");
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* not any further processing dummy messages */
 | 
					 | 
				
			||||||
	if (msg->data[0] == MGCP_DUMMY_LOAD)
 | 
					 | 
				
			||||||
		return osmux_handle_dummy(cfg, &addr, msg, MGCP_DEST_BTS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rem = msg->len;
 | 
					 | 
				
			||||||
	while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
 | 
					 | 
				
			||||||
		struct mgcp_endpoint *endp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Yes, we use MGCP_DEST_BTS to locate the origin */
 | 
					 | 
				
			||||||
		endp = endpoint_lookup(cfg, osmuxh->circuit_id,
 | 
					 | 
				
			||||||
				       &addr.sin_addr, MGCP_DEST_BTS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* FIXME: Get rid of CONN_ID_XXX! */
 | 
					 | 
				
			||||||
		conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
 | 
					 | 
				
			||||||
		if (!conn_net)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!endp) {
 | 
					 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			     "Cannot find an endpoint for circuit_id=%d\n",
 | 
					 | 
				
			||||||
			     osmuxh->circuit_id);
 | 
								     osmuxh->circuit_id);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}*/
 | 
				
			||||||
		if (endp_osmux_state_check(endp, conn_net, false) == 0) {
 | 
					
 | 
				
			||||||
			conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
 | 
							if (endp_osmux_state_check(conn_src->conn->endp, conn_src, false) == 0) {
 | 
				
			||||||
			conn_net->osmux.stats.chunks++;
 | 
								conn_src->osmux.stats.octets += osmux_chunk_length(msg, rem);
 | 
				
			||||||
			osmux_xfrm_output_sched(&conn_net->osmux.out, osmuxh);
 | 
								conn_src->osmux.stats.chunks++;
 | 
				
			||||||
 | 
								osmux_xfrm_output_sched(&conn_src->osmux.out, osmuxh);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rem = msg->len;
 | 
							rem = msg->len;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -502,22 +391,13 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(role) {
 | 
						osmux_fd.cb = osmux_read_fd_cb;
 | 
				
			||||||
	case OSMUX_ROLE_BSC:
 | 
					 | 
				
			||||||
		osmux_fd.cb = osmux_read_from_bsc_nat_cb;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case OSMUX_ROLE_BSC_NAT:
 | 
					 | 
				
			||||||
		osmux_fd.cb = osmux_read_from_bsc_cb;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "wrong role for OSMUX\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	osmux_fd.data = cfg;
 | 
						osmux_fd.data = cfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
 | 
						ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
 | 
				
			||||||
 | 
							     cfg->osmux_addr, cfg->osmux_port);
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
 | 
						mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
 | 
				
			||||||
@@ -525,11 +405,15 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ret = osmo_fd_register(&osmux_fd);
 | 
						ret = osmo_fd_register(&osmux_fd);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "cannot register OSMUX socket\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "cannot register OSMUX socket %s\n",
 | 
				
			||||||
 | 
							     osmo_sock_get_name2(osmux_fd.fd));
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cfg->osmux_init = 1;
 | 
						cfg->osmux_init = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_INFO, "OSMUX socket listening on %s\n",
 | 
				
			||||||
 | 
							 osmo_sock_get_name2(osmux_fd.fd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -537,7 +421,7 @@ int osmux_init(int role, struct mgcp_config *cfg)
 | 
				
			|||||||
 *  \param[in] endp mgcp endpoint (configuration)
 | 
					 *  \param[in] endp mgcp endpoint (configuration)
 | 
				
			||||||
 *  \param[in] conn connection to disable
 | 
					 *  \param[in] conn connection to disable
 | 
				
			||||||
 *  \param[in] addr IP address of remote OSMUX endpoint
 | 
					 *  \param[in] addr IP address of remote OSMUX endpoint
 | 
				
			||||||
 *  \param[in] port portnumber of the remote OSMUX endpoint
 | 
					 *  \param[in] port portnumber of the remote OSMUX endpoint (in network byte order)
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR */
 | 
					 *  \returns 0 on success, -1 on ERROR */
 | 
				
			||||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
					int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
		      struct in_addr *addr, uint16_t port)
 | 
							      struct in_addr *addr, uint16_t port)
 | 
				
			||||||
@@ -551,44 +435,46 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
	 *  overlapping RTP SSRC traveling to the BTSes behind the BSC,
 | 
						 *  overlapping RTP SSRC traveling to the BTSes behind the BSC,
 | 
				
			||||||
	 *  similarly, for flows traveling to the MSC.
 | 
						 *  similarly, for flows traveling to the MSC.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						struct in_addr addr_unset = {};
 | 
				
			||||||
	static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
						static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
 | 
				
			||||||
	uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 | 
						uint16_t osmux_dummy = endp->cfg->osmux_dummy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if osmux is enabled for the specified connection */
 | 
						/* Check if osmux is enabled for the specified connection */
 | 
				
			||||||
	if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
 | 
						if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "conn:%s didn't negotiate Osmux, state %d\n",
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "conn:%s didn't negotiate Osmux, state %d\n",
 | 
				
			||||||
			 mgcp_conn_dump(conn->conn), conn->osmux.state);
 | 
								 mgcp_conn_dump(conn->conn), conn->osmux.state);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Wait until we have the connection information from MDCX */
 | 
				
			||||||
 | 
						if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0) {
 | 
				
			||||||
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
				
			||||||
 | 
								"Osmux remote address/port still unknown\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
 | 
						conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
 | 
				
			||||||
	if (!conn->osmux.in) {
 | 
						if (!conn->osmux.in) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot allocate input osmux handle for conn:%s\n",
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								"Cannot allocate input osmux handle for conn:%s\n",
 | 
				
			||||||
			mgcp_conn_dump(conn->conn));
 | 
								mgcp_conn_dump(conn->conn));
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!osmux_xfrm_input_open_circuit(conn->osmux.in, conn->osmux.cid, osmux_dummy)) {
 | 
						if (osmux_xfrm_input_open_circuit(conn->osmux.in, conn->osmux.cid, osmux_dummy) < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u for conn:%s\n",
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								"Cannot open osmux circuit %u for conn:%s\n",
 | 
				
			||||||
		     conn->osmux.cid, mgcp_conn_dump(conn->conn));
 | 
							     conn->osmux.cid, mgcp_conn_dump(conn->conn));
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmux_xfrm_output_init(&conn->osmux.out,
 | 
						osmux_xfrm_output_init2(&conn->osmux.out,
 | 
				
			||||||
			       (conn->osmux.cid * rtp_ssrc_winlen) +
 | 
								       (conn->osmux.cid * rtp_ssrc_winlen) +
 | 
				
			||||||
			       (random() % rtp_ssrc_winlen));
 | 
								        (random() % rtp_ssrc_winlen),
 | 
				
			||||||
 | 
								       conn->end.codec->payload_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (endp->cfg->role) {
 | 
					 | 
				
			||||||
		case MGCP_BSC_NAT:
 | 
					 | 
				
			||||||
			conn->type = MGCP_OSMUX_BSC_NAT;
 | 
					 | 
				
			||||||
	osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
 | 
						osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
 | 
				
			||||||
							scheduled_tx_net_cb, endp);
 | 
									    scheduled_from_osmux_tx_rtp_cb, conn);
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case MGCP_BSC:
 | 
					 | 
				
			||||||
			conn->type = MGCP_OSMUX_BSC;
 | 
					 | 
				
			||||||
			osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
 | 
					 | 
				
			||||||
							scheduled_tx_bts_cb, endp);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->osmux.state = OSMUX_STATE_ENABLED;
 | 
						conn->osmux.state = OSMUX_STATE_ENABLED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -597,48 +483,65 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! disable OSXMUX circuit for a specified connection.
 | 
					/*! disable OSXMUX circuit for a specified connection.
 | 
				
			||||||
 *  \param[in] conn connection to disable */
 | 
					 *  \param[in] conn connection to disable */
 | 
				
			||||||
void osmux_disable_conn(struct mgcp_conn_rtp *conn)
 | 
					void conn_osmux_disable(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!conn)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->osmux.state != OSMUX_STATE_ENABLED)
 | 
						OSMO_ASSERT(conn->osmux.state != OSMUX_STATE_DISABLED);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_INFO, "Releasing connection %s using Osmux CID %u\n",
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
				
			||||||
	     conn->conn->id, conn->osmux.cid);
 | 
							"Releasing connection using Osmux CID %u\n", conn->osmux.cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
				
			||||||
		/* We are closing, we don't need pending RTP packets to be transmitted */
 | 
							/* We are closing, we don't need pending RTP packets to be transmitted */
 | 
				
			||||||
		osmux_xfrm_output_set_tx_cb(&conn->osmux.out, NULL, NULL);
 | 
							osmux_xfrm_output_set_tx_cb(&conn->osmux.out, NULL, NULL);
 | 
				
			||||||
		osmux_xfrm_output_flush(&conn->osmux.out);
 | 
							osmux_xfrm_output_flush(&conn->osmux.out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
 | 
							osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
 | 
				
			||||||
		conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
							conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
				
			||||||
	conn->osmux.cid = -1;
 | 
							conn_osmux_release_cid(conn);
 | 
				
			||||||
		osmux_handle_put(conn->osmux.in);
 | 
							osmux_handle_put(conn->osmux.in);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						conn_osmux_release_cid(conn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! relase OSXMUX cid, that had been allocated to this connection.
 | 
					/*! relase OSXMUX cid, that had been allocated to this connection.
 | 
				
			||||||
 *  \param[in] conn connection with OSMUX cid to release */
 | 
					 *  \param[in] conn connection with OSMUX cid to release */
 | 
				
			||||||
void osmux_release_cid(struct mgcp_conn_rtp *conn)
 | 
					void conn_osmux_release_cid(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!conn)
 | 
						if (conn->osmux.cid_allocated)
 | 
				
			||||||
		return;
 | 
							osmux_cid_pool_put(conn->osmux.cid);
 | 
				
			||||||
 | 
						conn->osmux.cid = 0;
 | 
				
			||||||
	if (conn->osmux.state != OSMUX_STATE_ENABLED)
 | 
						conn->osmux.cid_allocated = false;
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn->osmux.allocated_cid >= 0)
 | 
					 | 
				
			||||||
		osmux_put_cid(conn->osmux.allocated_cid);
 | 
					 | 
				
			||||||
	conn->osmux.allocated_cid = -1;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate OSXMUX cid to connection.
 | 
					/*! allocate OSXMUX cid to connection.
 | 
				
			||||||
 *  \param[in] conn connection for which we allocate the OSMUX cid*/
 | 
					 *  \param[in] conn connection for which we allocate the OSMUX cid
 | 
				
			||||||
void osmux_allocate_cid(struct mgcp_conn_rtp *conn)
 | 
					 * \param[in] osmux_cid OSMUX cid to allocate. -1 Means take next available one.
 | 
				
			||||||
 | 
					 * \returns Allocated OSMUX cid, -1 on error (no free  cids avail, or selected one is already taken).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmux_release_cid(conn);
 | 
						if (osmux_cid != -1 && osmux_cid_pool_allocated((uint8_t) osmux_cid)) {
 | 
				
			||||||
	conn->osmux.allocated_cid = osmux_get_cid();
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
				
			||||||
 | 
								 "Osmux CID %d already allocated!\n",
 | 
				
			||||||
 | 
								 osmux_cid);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmux_cid == -1) {
 | 
				
			||||||
 | 
							osmux_cid = osmux_cid_pool_get_next();
 | 
				
			||||||
 | 
							if (osmux_cid == -1) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
 | 
				
			||||||
 | 
									 "no available Osmux CID to allocate!\n");
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							osmux_cid_pool_get(osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn->osmux.cid = (uint8_t) osmux_cid;
 | 
				
			||||||
 | 
						conn->osmux.cid_allocated = true;
 | 
				
			||||||
 | 
						conn->type = MGCP_OSMUX_BSC;
 | 
				
			||||||
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! send RTP dummy packet to OSMUX connection port.
 | 
					/*! send RTP dummy packet to OSMUX connection port.
 | 
				
			||||||
@@ -647,7 +550,8 @@ void osmux_allocate_cid(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 *  \returns bytes sent, -1 on error */
 | 
					 *  \returns bytes sent, -1 on error */
 | 
				
			||||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char buf[1 + sizeof(uint8_t)];
 | 
						struct osmux_hdr *osmuxh;
 | 
				
			||||||
 | 
						int buf_len;
 | 
				
			||||||
	struct in_addr addr_unset = {};
 | 
						struct in_addr addr_unset = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*! The dummy packet will not be sent via the actual OSMUX connection,
 | 
						/*! The dummy packet will not be sent via the actual OSMUX connection,
 | 
				
			||||||
@@ -659,9 +563,6 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	 *  endpoint may have already punched the hole in the firewall. This
 | 
						 *  endpoint may have already punched the hole in the firewall. This
 | 
				
			||||||
	 *  approach is simple though. */
 | 
						 *  approach is simple though. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf[0] = MGCP_DUMMY_LOAD;
 | 
					 | 
				
			||||||
	memcpy(&buf[1], &conn->osmux.cid, sizeof(conn->osmux.cid));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Wait until we have the connection information from MDCX */
 | 
						/* Wait until we have the connection information from MDCX */
 | 
				
			||||||
	if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0)
 | 
						if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -669,12 +570,19 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	if (endp_osmux_state_check(endp, conn, true) < 0)
 | 
						if (endp_osmux_state_check(endp, conn, true) < 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						buf_len = sizeof(struct osmux_hdr) + osmo_amr_bytes(AMR_FT_0);
 | 
				
			||||||
	     "sending OSMUX dummy load to %s CID %u\n",
 | 
						osmuxh = (struct osmux_hdr *) alloca(buf_len);
 | 
				
			||||||
	     inet_ntoa(conn->end.addr), conn->osmux.cid);
 | 
						memset(osmuxh, 0, buf_len);
 | 
				
			||||||
 | 
						osmuxh->ft = OSMUX_FT_DUMMY;
 | 
				
			||||||
 | 
						osmuxh->amr_ft = AMR_FT_0;
 | 
				
			||||||
 | 
						osmuxh->circuit_id = conn->osmux.cid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
 | 
							 "sending OSMUX dummy load to %s:%u CID %u\n",
 | 
				
			||||||
 | 
							 inet_ntoa(conn->end.addr), ntohs(conn->end.rtp_port), conn->osmux.cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
 | 
						return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
 | 
				
			||||||
			     htons(endp->cfg->osmux_port), buf, sizeof(buf));
 | 
								     conn->end.rtp_port, (char*)osmuxh, buf_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* bsc-nat allocates/releases the Osmux circuit ID. +7 to round up to 8 bit boundary. */
 | 
					/* bsc-nat allocates/releases the Osmux circuit ID. +7 to round up to 8 bit boundary. */
 | 
				
			||||||
@@ -682,7 +590,7 @@ static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1 + 7) / 8];
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! count the number of taken OSMUX cids.
 | 
					/*! count the number of taken OSMUX cids.
 | 
				
			||||||
 *  \returns number of OSMUX cids in use */
 | 
					 *  \returns number of OSMUX cids in use */
 | 
				
			||||||
int osmux_used_cid(void)
 | 
					int osmux_cid_pool_count_used(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, j, used = 0;
 | 
						int i, j, used = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -698,7 +606,7 @@ int osmux_used_cid(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! take a free OSMUX cid.
 | 
					/*! take a free OSMUX cid.
 | 
				
			||||||
 *  \returns OSMUX cid */
 | 
					 *  \returns OSMUX cid */
 | 
				
			||||||
int osmux_get_cid(void)
 | 
					int osmux_cid_pool_get_next(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i, j;
 | 
						int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -718,10 +626,24 @@ int osmux_get_cid(void)
 | 
				
			|||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! take a specific OSMUX cid.
 | 
				
			||||||
 | 
					 *  \param[in] osmux_cid OSMUX cid */
 | 
				
			||||||
 | 
					void osmux_cid_pool_get(uint8_t osmux_cid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "Allocating Osmux CID %u from pool\n", osmux_cid);
 | 
				
			||||||
 | 
						osmux_cid_bitmap[osmux_cid / 8] |= (1 << (osmux_cid % 8));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! put back a no longer used OSMUX cid.
 | 
					/*! put back a no longer used OSMUX cid.
 | 
				
			||||||
 *  \param[in] osmux_cid OSMUX cid */
 | 
					 *  \param[in] osmux_cid OSMUX cid */
 | 
				
			||||||
void osmux_put_cid(uint8_t osmux_cid)
 | 
					void osmux_cid_pool_put(uint8_t osmux_cid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
 | 
				
			||||||
	osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
 | 
						osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! check if OSMUX cid is already taken */
 | 
				
			||||||
 | 
					bool osmux_cid_pool_allocated(uint8_t osmux_cid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !!(osmux_cid_bitmap[osmux_cid / 8] & (1 << (osmux_cid % 8)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,17 +147,15 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	struct mgcp_conn_rtp *conn_dst = conn;
 | 
						struct mgcp_conn_rtp *conn_dst = conn;
 | 
				
			||||||
	struct mgcp_conn *_conn;
 | 
						struct mgcp_conn *_conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->type != MGCP_RTP_DEFAULT) {
 | 
						if (conn->type != MGCP_RTP_DEFAULT && !mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		     "endpoint:%x RTP-setup: Endpoint is not configured as RTP default, stopping here!\n",
 | 
								 "RTP-setup: Endpoint is not configured as RTP default, stopping here!\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->conn->mode == MGCP_CONN_LOOPBACK) {
 | 
						if (conn->conn->mode == MGCP_CONN_LOOPBACK) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		     "endpoint:%x RTP-setup: Endpoint is in loopback mode, stopping here!\n",
 | 
								 "RTP-setup: Endpoint is in loopback mode, stopping here!\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,13 +223,13 @@ static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
 | 
				
			|||||||
	len = snprintf((char *)res->data, 2048, "%d %s%s%s\r\n%s",
 | 
						len = snprintf((char *)res->data, 2048, "%d %s%s%s\r\n%s",
 | 
				
			||||||
		       code, trans, txt, param ? param : "", sdp ? sdp : "");
 | 
							       code, trans, txt, param ? param : "", sdp ? sdp : "");
 | 
				
			||||||
	if (len < 0) {
 | 
						if (len < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Failed to sprintf MGCP response.\n");
 | 
				
			||||||
		msgb_free(res);
 | 
							msgb_free(res);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res->l2h = msgb_put(res, len);
 | 
						res->l2h = msgb_put(res, len);
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Generated response: code=%d\n", code);
 | 
				
			||||||
	mgcp_disp_msg(res->l2h, msgb_l2len(res), "Generated response");
 | 
						mgcp_disp_msg(res->l2h, msgb_l2len(res), "Generated response");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
@@ -302,11 +300,13 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
					     const char *trans_id,
 | 
										     const char *trans_id,
 | 
				
			||||||
					     bool add_conn_params)
 | 
										     bool add_conn_params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* TODO: we may want to define another local_ip_osmux var to us for
 | 
				
			||||||
 | 
						   OSMUX connections. Perhaps adding a new internal API to get it based
 | 
				
			||||||
 | 
						   on conn type */
 | 
				
			||||||
	const char *addr = endp->cfg->local_ip;
 | 
						const char *addr = endp->cfg->local_ip;
 | 
				
			||||||
	struct msgb *sdp;
 | 
						struct msgb *sdp;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct msgb *result;
 | 
						struct msgb *result;
 | 
				
			||||||
	char osmux_extension[strlen("X-Osmux: 255") + 1];
 | 
					 | 
				
			||||||
	char local_ip_addr[INET_ADDRSTRLEN];
 | 
						char local_ip_addr[INET_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdp = msgb_alloc_headroom(4096, 128, "sdp record");
 | 
						sdp = msgb_alloc_headroom(4096, 128, "sdp record");
 | 
				
			||||||
@@ -318,13 +318,6 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
		addr = local_ip_addr;
 | 
							addr = local_ip_addr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
 | 
					 | 
				
			||||||
		sprintf(osmux_extension, "X-Osmux: %u", conn->osmux.cid);
 | 
					 | 
				
			||||||
		conn->osmux.state = OSMUX_STATE_ACTIVATING;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		osmux_extension[0] = '\0';
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Attach optional connection parameters */
 | 
						/* Attach optional connection parameters */
 | 
				
			||||||
	if (add_conn_params) {
 | 
						if (add_conn_params) {
 | 
				
			||||||
		rc = add_params(sdp, endp, conn);
 | 
							rc = add_params(sdp, endp, conn);
 | 
				
			||||||
@@ -333,8 +326,8 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Attach optional OSMUX parameters */
 | 
						/* Attach optional OSMUX parameters */
 | 
				
			||||||
	if (conn->osmux.state == OSMUX_STATE_NEGOTIATING) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "%s\r\n", osmux_extension);
 | 
							rc = msgb_printf(sdp, "X-Osmux: %u\r\n", conn->osmux.cid);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -430,15 +423,15 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
/* AUEP command handler, processes the received command */
 | 
					/* AUEP command handler, processes the received command */
 | 
				
			||||||
static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
 | 
					static struct msgb *handle_audit_endpoint(struct mgcp_parse_data *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
						LOGPENDP(p->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
				
			||||||
	return create_ok_response(p->endp, 200, "AUEP", p->trans);
 | 
						return create_ok_response(p->endp, 200, "AUEP", p->trans);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Try to find a free port by attempting to bind on it. Also handle the
 | 
					/* Try to find a free port by attempting to bind on it. Also handle the
 | 
				
			||||||
 * counter that points on the next free port. Since we have a pointer
 | 
					 * counter that points on the next free port. Since we have a pointer
 | 
				
			||||||
 * to the next free port, binding should in work on the first attempt in
 | 
					 * to the next free port, binding should in work on the first attempt in
 | 
				
			||||||
 * general. In case of failure the next port is tryed until the whole port
 | 
					 * general. In case of failure the next port is tried until the whole port
 | 
				
			||||||
 * range is tryed once. */
 | 
					 * range is tried once. */
 | 
				
			||||||
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
@@ -469,9 +462,9 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
	     "Allocating a RTP/RTCP port failed %u times 0x%x.\n",
 | 
						     "Allocating a RTP/RTCP port failed %u times.\n",
 | 
				
			||||||
	     tries, ENDPOINT_NUMBER(endp));
 | 
						     tries);
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -566,7 +559,7 @@ int check_local_cx_options(void *ctx, const char *options)
 | 
				
			|||||||
		 * before. If yes, we must bail, an LCO must only appear once
 | 
							 * before. If yes, we must bail, an LCO must only appear once
 | 
				
			||||||
		 * in the LCO string */
 | 
							 * in the LCO string */
 | 
				
			||||||
		for (i = 0; i < lco_seen_n; i++) {
 | 
							for (i = 0; i < lco_seen_n; i++) {
 | 
				
			||||||
			if (strcmp(lco_seen[i], lco_identifier) == 0)
 | 
								if (strcasecmp(lco_seen[i], lco_identifier) == 0)
 | 
				
			||||||
				goto error;
 | 
									goto error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		lco_seen[lco_seen_n] = lco_identifier;
 | 
							lco_seen[lco_seen_n] = lco_identifier;
 | 
				
			||||||
@@ -597,8 +590,9 @@ error:
 | 
				
			|||||||
static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
					static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			||||||
				 const char *options)
 | 
									 const char *options)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *p_opt, *a_opt;
 | 
						char *lco_id;
 | 
				
			||||||
	char codec[17];
 | 
						char codec[17];
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!options)
 | 
						if (!options)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -615,18 +609,37 @@ static int set_local_cx_options(void *ctx, struct mgcp_lco *lco,
 | 
				
			|||||||
	talloc_free(lco->string);
 | 
						talloc_free(lco->string);
 | 
				
			||||||
	lco->string = talloc_strdup(ctx, options);
 | 
						lco->string = talloc_strdup(ctx, options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p_opt = strstr(lco->string, "p:");
 | 
						lco_id = lco->string;
 | 
				
			||||||
	if (p_opt && sscanf(p_opt, "p:%d-%d",
 | 
						while ((lco_id = get_lco_identifier(lco_id))) {
 | 
				
			||||||
 | 
							switch (tolower(lco_id[0])) {
 | 
				
			||||||
 | 
							case 'p':
 | 
				
			||||||
 | 
								if (sscanf(lco_id + 1, ":%d-%d",
 | 
				
			||||||
				   &lco->pkt_period_min, &lco->pkt_period_max) == 1)
 | 
									   &lco->pkt_period_min, &lco->pkt_period_max) == 1)
 | 
				
			||||||
				lco->pkt_period_max = lco->pkt_period_min;
 | 
									lco->pkt_period_max = lco->pkt_period_min;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'a':
 | 
				
			||||||
			/* FIXME: LCO also supports the negotiation of more then one codec.
 | 
								/* FIXME: LCO also supports the negotiation of more then one codec.
 | 
				
			||||||
			 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
								 * (e.g. a:PCMU;G726-32) But this implementation only supports a single
 | 
				
			||||||
			 * codec only. */
 | 
								 * codec only. */
 | 
				
			||||||
	a_opt = strstr(lco->string, "a:");
 | 
								if (sscanf(lco_id + 1, ":%16[^,]", codec) == 1) {
 | 
				
			||||||
	if (a_opt && sscanf(a_opt, "a:%16[^,]", codec) == 1) {
 | 
					 | 
				
			||||||
				talloc_free(lco->codec);
 | 
									talloc_free(lco->codec);
 | 
				
			||||||
		lco->codec = talloc_strdup(ctx, codec);
 | 
									/* MGCP header is case insensive, and we'll need
 | 
				
			||||||
 | 
									   codec in uppercase when using it later: */
 | 
				
			||||||
 | 
									len = strlen(codec);
 | 
				
			||||||
 | 
									lco->codec = talloc_size(ctx, len + 1);
 | 
				
			||||||
 | 
									osmo_str_toupper_buf(lco->codec, len + 1, codec);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
 | 
								     "LCO: unhandled option: '%c'/%d in \"%s\"\n",
 | 
				
			||||||
 | 
								     *lco_id, *lco_id, lco->string);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							lco_id = strchr(lco_id, ',');
 | 
				
			||||||
 | 
							if (!lco_id)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						LOGP(DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
@@ -652,8 +665,9 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rtp->force_aligned_timing = tcfg->force_aligned_timing;
 | 
						rtp->force_aligned_timing = tcfg->force_aligned_timing;
 | 
				
			||||||
	rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
 | 
						rtp->force_constant_ssrc = patch_ssrc ? 1 : 0;
 | 
				
			||||||
 | 
						rtp->rfc5993_hr_convert = tcfg->rfc5993_hr_convert;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(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),
 | 
							 ntohs(rtp->rtp_port),
 | 
				
			||||||
		 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
							 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
				
			||||||
@@ -679,14 +693,19 @@ uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	    rtp->codec->frame_duration_den;
 | 
						    rtp->codec->frame_duration_den;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*! Initializes osmux socket if not yet initialized. Parses Osmux CID from MGCP line.
 | 
				
			||||||
 | 
					 *  \param[in] endp Endpoint willing to initialize osmux
 | 
				
			||||||
 | 
					 *  \param[in] line Line X-Osmux from MGCP header msg to parse
 | 
				
			||||||
 | 
					 *  \returns OSMUX CID, -1 for wildcard, -2 on parse error, -3 on osmux initalize error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
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->cfg->osmux_init) {
 | 
						if (!endp->cfg->osmux_init) {
 | 
				
			||||||
		if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
 | 
							if (osmux_init(OSMUX_ROLE_BSC, endp->cfg) < 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
				
			||||||
			return -1;
 | 
								return -3;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
 | 
							LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "OSMUX socket has been set up\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_parse_osmux_cid(line);
 | 
						return mgcp_parse_osmux_cid(line);
 | 
				
			||||||
@@ -712,9 +731,8 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
		mgcp_codec_reset_all(conn);
 | 
							mgcp_codec_reset_all(conn);
 | 
				
			||||||
		rc = mgcp_parse_sdp_data(endp, conn, p);
 | 
							rc = mgcp_parse_sdp_data(endp, conn, p);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP,  LOGL_ERROR,
 | 
				
			||||||
			     "%s: endpoint:%x sdp not parseable\n", cmd,
 | 
									 "%s: sdp not parseable\n", cmd);
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* See also RFC 3661: Protocol error */
 | 
								/* See also RFC 3661: Protocol error */
 | 
				
			||||||
			return 510;
 | 
								return 510;
 | 
				
			||||||
@@ -723,7 +741,7 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
		/* When no SDP is available, we use the codec information from
 | 
							/* When no SDP is available, we use the codec information from
 | 
				
			||||||
		 * the local connection options (if present) */
 | 
							 * the local connection options (if present) */
 | 
				
			||||||
		mgcp_codec_reset_all(conn);
 | 
							mgcp_codec_reset_all(conn);
 | 
				
			||||||
		rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec);
 | 
							rc = mgcp_codec_add(conn, PTYPE_UNDEFINED, endp->local_options.codec, NULL);
 | 
				
			||||||
		if (rc != 0)
 | 
							if (rc != 0)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -734,7 +752,7 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
		 * than it makes sense to pick a sane default: (payload-type 0,
 | 
							 * than it makes sense to pick a sane default: (payload-type 0,
 | 
				
			||||||
		 * PCMU), see also: OS#2658 */
 | 
							 * PCMU), see also: OS#2658 */
 | 
				
			||||||
		mgcp_codec_reset_all(conn);
 | 
							mgcp_codec_reset_all(conn);
 | 
				
			||||||
		rc = mgcp_codec_add(conn, 0, NULL);
 | 
							rc = mgcp_codec_add(conn, 0, NULL, NULL);
 | 
				
			||||||
		if (rc != 0)
 | 
							if (rc != 0)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -746,9 +764,8 @@ static int handle_codec_info(struct mgcp_conn_rtp *conn,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
	     "%s: endpoint:0x%x codec negotiation failure\n", cmd,
 | 
						     "%s: codec negotiation failure\n", cmd);
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* See also RFC 3661: Codec negotiation failure */
 | 
						/* See also RFC 3661: Codec negotiation failure */
 | 
				
			||||||
	return 534;
 | 
						return 534;
 | 
				
			||||||
@@ -768,11 +785,10 @@ static bool parse_x_osmo_ign(struct mgcp_endpoint *endp, char *line)
 | 
				
			|||||||
		if (!token)
 | 
							if (!token)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!strcmp(token, "C"))
 | 
							if (!strcasecmp(token, "C"))
 | 
				
			||||||
			endp->x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
 | 
								endp->x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR, "endpoint 0x%x: received unknown X-Osmo-IGN item '%s'\n",
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token);
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp), token);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
@@ -789,20 +805,20 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	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 = -1;
 | 
						int have_sdp = 0, 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];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse CallID C: and LocalParameters L: */
 | 
						/* parse CallID C: and LocalParameters L: */
 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
		if (!mgcp_check_param(endp, line))
 | 
							if (!mgcp_check_param(endp, line))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'L':
 | 
							case 'L':
 | 
				
			||||||
			local_options = (const char *)line + 3;
 | 
								local_options = (const char *)line + 3;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -820,7 +836,7 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
			mode = (const char *)line + 3;
 | 
								mode = (const char *)line + 3;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'X':
 | 
							case 'X':
 | 
				
			||||||
			if (strncmp("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 (!p->endp->cfg->osmux)
 | 
									if (!p->endp->cfg->osmux)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
@@ -837,9 +853,8 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
			have_sdp = 1;
 | 
								have_sdp = 1;
 | 
				
			||||||
			goto mgcp_header_done;
 | 
								goto mgcp_header_done;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "CRCX: endpoint:%x unhandled option: '%c'/%d\n",
 | 
									 "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp), *line, *line);
 | 
					 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_UNHANDLED_PARAM]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_UNHANDLED_PARAM]);
 | 
				
			||||||
			return create_err_response(NULL, 539, "CRCX", p->trans);
 | 
								return create_err_response(NULL, 539, "CRCX", p->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -849,26 +864,24 @@ static struct msgb *handle_create_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
mgcp_header_done:
 | 
					mgcp_header_done:
 | 
				
			||||||
	/* Check parameters */
 | 
						/* Check parameters */
 | 
				
			||||||
	if (!callid) {
 | 
						if (!callid) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:%x insufficient parameters, missing callid\n",
 | 
								 "CRCX: insufficient parameters, missing callid\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_MISSING_CALLID]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_MISSING_CALLID]);
 | 
				
			||||||
		return create_err_response(endp, 516, "CRCX", p->trans);
 | 
							return create_err_response(endp, 516, "CRCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mode) {
 | 
						if (!mode) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:%x insufficient parameters, missing mode\n",
 | 
								 "CRCX: insufficient parameters, missing mode\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_INVALID_MODE]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_INVALID_MODE]);
 | 
				
			||||||
		return create_err_response(endp, 517, "CRCX", p->trans);
 | 
							return create_err_response(endp, 517, "CRCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if we are able to accept the creation of another connection */
 | 
						/* Check if we are able to accept the creation of another connection */
 | 
				
			||||||
	if (llist_count(&endp->conns) >= endp->type->max_conns) {
 | 
						if (llist_count(&endp->conns) >= endp->type->max_conns) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:%x endpoint full, max. %i connections allowed!\n",
 | 
								"CRCX: endpoint full, max. %i connections allowed!\n",
 | 
				
			||||||
		     endp->type->max_conns, ENDPOINT_NUMBER(endp));
 | 
								endp->type->max_conns);
 | 
				
			||||||
		if (tcfg->force_realloc) {
 | 
							if (tcfg->force_realloc) {
 | 
				
			||||||
			/* There is no more room for a connection, make some
 | 
								/* There is no more room for a connection, make some
 | 
				
			||||||
			 * room by blindly tossing the oldest of the two two
 | 
								 * room by blindly tossing the oldest of the two two
 | 
				
			||||||
@@ -885,9 +898,9 @@ mgcp_header_done:
 | 
				
			|||||||
	/* Check if this endpoint already serves a call, if so, check if the
 | 
						/* Check if this endpoint already serves a call, if so, check if the
 | 
				
			||||||
	 * callids match up so that we are sure that this is our call */
 | 
						 * callids match up so that we are sure that this is our call */
 | 
				
			||||||
	if (endp->callid && mgcp_verify_call_id(endp, callid)) {
 | 
						if (endp->callid && mgcp_verify_call_id(endp, callid)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:0x%x allready seized by other call (%s)\n",
 | 
								 "CRCX: already seized by other call (%s)\n",
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp), endp->callid);
 | 
								 endp->callid);
 | 
				
			||||||
		if (tcfg->force_realloc)
 | 
							if (tcfg->force_realloc)
 | 
				
			||||||
			/* This is not our call, toss everything by releasing
 | 
								/* This is not our call, toss everything by releasing
 | 
				
			||||||
			 * the entire endpoint. (rude!) */
 | 
								 * the entire endpoint. (rude!) */
 | 
				
			||||||
@@ -908,9 +921,8 @@ mgcp_header_done:
 | 
				
			|||||||
	snprintf(conn_name, sizeof(conn_name), "%s", callid);
 | 
						snprintf(conn_name, sizeof(conn_name), "%s", callid);
 | 
				
			||||||
	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
 | 
						_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, conn_name);
 | 
				
			||||||
	if (!_conn) {
 | 
						if (!_conn) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:0x%x unable to allocate RTP connection\n",
 | 
								 "CRCX: unable to allocate RTP connection\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_ALLOC_CONN]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_ALLOC_CONN]);
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -927,13 +939,15 @@ mgcp_header_done:
 | 
				
			|||||||
	/* Annotate Osmux circuit ID and set it to negotiating state until this
 | 
						/* Annotate Osmux circuit ID and set it to negotiating state until this
 | 
				
			||||||
	 * is fully set up from the dummy load. */
 | 
						 * is fully set up from the dummy load. */
 | 
				
			||||||
	conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
						conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
				
			||||||
	if (osmux_cid >= 0) {
 | 
						if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
 | 
				
			||||||
		conn->osmux.cid = osmux_cid;
 | 
							conn->osmux.state = OSMUX_STATE_ACTIVATING;
 | 
				
			||||||
		conn->osmux.state = OSMUX_STATE_NEGOTIATING;
 | 
							if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
 | 
				
			||||||
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_NO_OSMUX]);
 | 
				
			||||||
 | 
								goto error2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
 | 
						} else if (endp->cfg->osmux == OSMUX_USAGE_ONLY) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:0x%x osmux only and no osmux offered\n",
 | 
								 "CRCX: osmux only and no osmux offered\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_NO_OSMUX]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_NO_OSMUX]);
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -943,9 +957,8 @@ mgcp_header_done:
 | 
				
			|||||||
		rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
							rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
				
			||||||
					  &endp->local_options, local_options);
 | 
										  &endp->local_options, local_options);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "CRCX: endpoint:%x inavlid local connection options!\n",
 | 
									 "CRCX: inavlid local connection options!\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			error_code = rc;
 | 
								error_code = rc;
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS]);
 | 
				
			||||||
			goto error2;
 | 
								goto error2;
 | 
				
			||||||
@@ -975,9 +988,8 @@ mgcp_header_done:
 | 
				
			|||||||
	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) {
 | 
						    && conn->end.rtp_port == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:%x selected connection mode type requires an opposite end!\n",
 | 
								 "CRCX: selected connection mode type requires an opposite end!\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		error_code = 527;
 | 
							error_code = 527;
 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC]);
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
@@ -989,9 +1001,8 @@ mgcp_header_done:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (setup_rtp_processing(endp, conn) != 0) {
 | 
						if (setup_rtp_processing(endp, conn) != 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "CRCX: endpoint:0x%x could not start RTP processing!\n",
 | 
								 "CRCX: could not start RTP processing!\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_START_RTP]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_START_RTP]);
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1003,9 +1014,8 @@ mgcp_header_done:
 | 
				
			|||||||
				       MGCP_ENDP_CRCX, p->trans);
 | 
									       MGCP_ENDP_CRCX, p->trans);
 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "CRCX: endpoint:0x%x CRCX rejected by policy\n",
 | 
									 "CRCX: CRCX rejected by policy\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			mgcp_endp_release(endp);
 | 
								mgcp_endp_release(endp);
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_REJECTED_BY_POLICY]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_FAIL_REJECTED_BY_POLICY]);
 | 
				
			||||||
			return create_err_response(endp, 400, "CRCX", p->trans);
 | 
								return create_err_response(endp, 400, "CRCX", p->trans);
 | 
				
			||||||
@@ -1020,9 +1030,8 @@ mgcp_header_done:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
	     "CRCX: endpoint:0x%x Creating connection: CI: %s port: %u\n",
 | 
							 "CRCX: Creating connection: port: %u\n", conn->end.local_port);
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), conn->conn->id, conn->end.local_port);
 | 
					 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
		p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
 | 
							p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1032,16 +1041,14 @@ mgcp_header_done:
 | 
				
			|||||||
	    && tcfg->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    && tcfg->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "CRCX: endpoint:0x%x connection successfully created\n",
 | 
							 "CRCX: connection successfully created\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]);
 | 
						rate_ctr_inc(&rate_ctrs->ctr[MGCP_CRCX_SUCCESS]);
 | 
				
			||||||
	return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
 | 
						return create_response_with_sdp(endp, conn, "CRCX", p->trans, true);
 | 
				
			||||||
error2:
 | 
					error2:
 | 
				
			||||||
	mgcp_endp_release(endp);
 | 
						mgcp_endp_release(endp);
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "CRCX: endpoint:0x%x unable to create connection\n",
 | 
							 "CRCX: unable to create connection\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	return create_err_response(endp, error_code, "CRCX", p->trans);
 | 
						return create_err_response(endp, error_code, "CRCX", p->trans);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1063,23 +1070,22 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	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 rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (endp->wildcarded_req) {
 | 
						if (endp->wildcarded_req) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "MDCX: endpoint:0x%x wildcarded endpoint names not supported.\n",
 | 
								 "MDCX: wildcarded endpoint names not supported.\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_WILDCARD]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_WILDCARD]);
 | 
				
			||||||
		return create_err_response(endp, 507, "MDCX", p->trans);
 | 
							return create_err_response(endp, 507, "MDCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_count(&endp->conns) <= 0) {
 | 
						if (llist_count(&endp->conns) <= 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "MDCX: endpoint:0x%x endpoint is not holding a connection.\n",
 | 
								 "MDCX: endpoint is not holding a connection.\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_CONN]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_CONN]);
 | 
				
			||||||
		return create_err_response(endp, 400, "MDCX", p->trans);
 | 
							return create_err_response(endp, 400, "MDCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1088,7 +1094,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
		if (!mgcp_check_param(endp, line))
 | 
							if (!mgcp_check_param(endp, line))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'C':
 | 
							case 'C':
 | 
				
			||||||
			if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
								if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
				
			||||||
				rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_CALLID]);
 | 
									rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_CALLID]);
 | 
				
			||||||
@@ -1110,16 +1116,26 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
			mode = (const char *)line + 3;
 | 
								mode = (const char *)line + 3;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'Z':
 | 
							case 'Z':
 | 
				
			||||||
			silent = strcmp("noanswer", line + 3) == 0;
 | 
								silent = strcasecmp("noanswer", line + 3) == 0;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'X':
 | 
				
			||||||
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
 | 
									/* If osmux is disabled, just skip setting it up */
 | 
				
			||||||
 | 
									if (!p->endp->cfg->osmux)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									osmux_cid = mgcp_osmux_setup(endp, line);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case '\0':
 | 
							case '\0':
 | 
				
			||||||
			have_sdp = 1;
 | 
								have_sdp = 1;
 | 
				
			||||||
			goto mgcp_header_done;
 | 
								goto mgcp_header_done;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "MDCX: endpoint:0x%x Unhandled MGCP option: '%c'/%d\n",
 | 
									 "MDCX: Unhandled MGCP option: '%c'/%d\n",
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp), line[0], line[0]);
 | 
									 line[0], line[0]);
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_UNHANDLED_PARAM]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_UNHANDLED_PARAM]);
 | 
				
			||||||
			return create_err_response(NULL, 539, "MDCX", p->trans);
 | 
								return create_err_response(NULL, 539, "MDCX", p->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -1128,9 +1144,8 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
mgcp_header_done:
 | 
					mgcp_header_done:
 | 
				
			||||||
	if (!conn_id) {
 | 
						if (!conn_id) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "MDCX: endpoint:0x%x insufficient parameters, missing ci (connectionIdentifier)\n",
 | 
								 "MDCX: insufficient parameters, missing ci (connectionIdentifier)\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_CONNID]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_CONNID]);
 | 
				
			||||||
		return create_err_response(endp, 515, "MDCX", p->trans);
 | 
							return create_err_response(endp, 515, "MDCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1141,6 +1156,8 @@ mgcp_header_done:
 | 
				
			|||||||
		return create_err_response(endp, 400, "MDCX", p->trans);
 | 
							return create_err_response(endp, 400, "MDCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mgcp_conn_watchdog_kick(conn->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mode) {
 | 
						if (mode) {
 | 
				
			||||||
		if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
 | 
							if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_MODE]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_MODE]);
 | 
				
			||||||
@@ -1155,9 +1172,8 @@ mgcp_header_done:
 | 
				
			|||||||
		rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
							rc = set_local_cx_options(endp->tcfg->endpoints,
 | 
				
			||||||
					  &endp->local_options, local_options);
 | 
										  &endp->local_options, local_options);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			     "MDCX: endpoint:%x invalid local connection options!\n",
 | 
									 "MDCX: invalid local connection options!\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			error_code = rc;
 | 
								error_code = rc;
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS]);
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
@@ -1176,14 +1192,32 @@ mgcp_header_done:
 | 
				
			|||||||
	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) {
 | 
						    && conn->end.rtp_port == 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "MDCX: endpoint:%x selected connection mode type requires an opposite end!\n",
 | 
								 "MDCX: selected connection mode type requires an opposite end!\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		error_code = 527;
 | 
							error_code = 527;
 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC]);
 | 
				
			||||||
		goto error3;
 | 
							goto error3;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
 | 
							OSMO_ASSERT(conn->osmux.cid_allocated);
 | 
				
			||||||
 | 
							if (osmux_cid < -1) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									 "MDCX: Failed to parse Osmux CID!\n");
 | 
				
			||||||
 | 
								goto error3;
 | 
				
			||||||
 | 
							} else if (osmux_cid == -1) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									 "MDCX: wilcard in MDCX is not supported!\n");
 | 
				
			||||||
 | 
								goto error3;
 | 
				
			||||||
 | 
							} else if (osmux_cid != (int) conn->osmux.cid) {
 | 
				
			||||||
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									 "MDCX: changing already allocated CID is not supported!\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. */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (setup_rtp_processing(endp, conn) != 0) {
 | 
						if (setup_rtp_processing(endp, conn) != 0) {
 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_START_RTP]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_START_RTP]);
 | 
				
			||||||
@@ -1198,9 +1232,8 @@ mgcp_header_done:
 | 
				
			|||||||
				       MGCP_ENDP_MDCX, p->trans);
 | 
									       MGCP_ENDP_MDCX, p->trans);
 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "MDCX: endpoint:0x%x rejected by policy\n",
 | 
									 "MDCX: rejected by policy\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_REJECTED_BY_POLICY]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_FAIL_REJECTED_BY_POLICY]);
 | 
				
			||||||
			if (silent)
 | 
								if (silent)
 | 
				
			||||||
				goto out_silent;
 | 
									goto out_silent;
 | 
				
			||||||
@@ -1208,9 +1241,8 @@ mgcp_header_done:
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
		case MGCP_POLICY_DEFER:
 | 
							case MGCP_POLICY_DEFER:
 | 
				
			||||||
			/* stop processing */
 | 
								/* stop processing */
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_DEBUG,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
			     "MDCX: endpoint:0x%x deferred by policy\n",
 | 
									 "MDCX: deferred by policy\n");
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_DEFERRED_BY_POLICY]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_MDCX_DEFERRED_BY_POLICY]);
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -1223,9 +1255,8 @@ mgcp_header_done:
 | 
				
			|||||||
	mgcp_rtp_end_config(endp, 1, &conn->end);
 | 
						mgcp_rtp_end_config(endp, 1, &conn->end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* modify */
 | 
						/* modify */
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
	     "MDCX: endpoint:0x%x modified conn:%s\n",
 | 
							 "MDCX: modified conn:%s\n", mgcp_conn_dump(conn->conn));
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
 | 
					 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
							p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp),
 | 
				
			||||||
				  MGCP_ENDP_MDCX);
 | 
									  MGCP_ENDP_MDCX);
 | 
				
			||||||
@@ -1240,16 +1271,14 @@ mgcp_header_done:
 | 
				
			|||||||
	if (silent)
 | 
						if (silent)
 | 
				
			||||||
		goto out_silent;
 | 
							goto out_silent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "MDCX: endpoint:0x%x connection successfully modified\n",
 | 
							 "MDCX: connection successfully modified\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
 | 
						return create_response_with_sdp(endp, conn, "MDCX", p->trans, false);
 | 
				
			||||||
error3:
 | 
					error3:
 | 
				
			||||||
	return create_err_response(endp, error_code, "MDCX", p->trans);
 | 
						return create_err_response(endp, error_code, "MDCX", p->trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_silent:
 | 
					out_silent:
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "MDCX: endpoint:0x%x silent exit\n",
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "MDCX: silent exit\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1266,23 +1295,20 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	const char *conn_id = NULL;
 | 
						const char *conn_id = NULL;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "DLCX: endpoint:0x%x deleting connection ...\n",
 | 
							 "DLCX: deleting connection ...\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (endp->wildcarded_req) {
 | 
						if (endp->wildcarded_req) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "DLCX: endpoint:0x%x wildcarded endpoint names not supported.\n",
 | 
								 "DLCX: wildcarded endpoint names not supported.\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_WILDCARD]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_WILDCARD]);
 | 
				
			||||||
		return create_err_response(endp, 507, "DLCX", p->trans);
 | 
							return create_err_response(endp, 507, "DLCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_count(&endp->conns) <= 0) {
 | 
						if (llist_count(&endp->conns) <= 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
		     "DLCX: endpoint:0x%x endpoint is not holding a connection.\n",
 | 
								 "DLCX: endpoint is not holding a connection.\n");
 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
		rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_NO_CONN]);
 | 
							rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_NO_CONN]);
 | 
				
			||||||
		return create_err_response(endp, 515, "DLCX", p->trans);
 | 
							return create_err_response(endp, 515, "DLCX", p->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1291,7 +1317,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
		if (!mgcp_check_param(endp, line))
 | 
							if (!mgcp_check_param(endp, line))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'C':
 | 
							case 'C':
 | 
				
			||||||
			if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
								if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
				
			||||||
				error_code = 516;
 | 
									error_code = 516;
 | 
				
			||||||
@@ -1307,12 +1333,12 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'Z':
 | 
							case 'Z':
 | 
				
			||||||
			silent = strcmp("noanswer", line + 3) == 0;
 | 
								silent = strcasecmp("noanswer", line + 3) == 0;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "DLCX: endpoint:0x%x Unhandled MGCP option: '%c'/%d\n",
 | 
									 "DLCX: Unhandled MGCP option: '%c'/%d\n",
 | 
				
			||||||
			     ENDPOINT_NUMBER(endp), line[0], line[0]);
 | 
									 line[0], line[0]);
 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_UNHANDLED_PARAM]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_UNHANDLED_PARAM]);
 | 
				
			||||||
			return create_err_response(NULL, 539, "DLCX", p->trans);
 | 
								return create_err_response(NULL, 539, "DLCX", p->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -1326,9 +1352,7 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
				       MGCP_ENDP_DLCX, p->trans);
 | 
									       MGCP_ENDP_DLCX, p->trans);
 | 
				
			||||||
		switch (rc) {
 | 
							switch (rc) {
 | 
				
			||||||
		case MGCP_POLICY_REJECT:
 | 
							case MGCP_POLICY_REJECT:
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "DLCX: rejected by policy\n");
 | 
				
			||||||
			     "DLCX: endpoint:0x%x rejected by policy\n",
 | 
					 | 
				
			||||||
			     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
			rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_REJECTED_BY_POLICY]);
 | 
								rate_ctr_inc(&rate_ctrs->ctr[MGCP_DLCX_FAIL_REJECTED_BY_POLICY]);
 | 
				
			||||||
			if (silent)
 | 
								if (silent)
 | 
				
			||||||
				goto out_silent;
 | 
									goto out_silent;
 | 
				
			||||||
@@ -1350,9 +1374,9 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	 * RFC3435 Section F.7) */
 | 
						 * RFC3435 Section F.7) */
 | 
				
			||||||
	if (!conn_id) {
 | 
						if (!conn_id) {
 | 
				
			||||||
		int num_conns = llist_count(&endp->conns);
 | 
							int num_conns = llist_count(&endp->conns);
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_NOTICE,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		     "DLCX: endpoint:0x%x missing ci (connectionIdentifier), will remove all connections (%d total) at once\n",
 | 
								 "DLCX: missing ci (connectionIdentifier), will remove all connections (%d total) at once\n",
 | 
				
			||||||
		     num_conns, ENDPOINT_NUMBER(endp));
 | 
								 num_conns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (num_conns > 0)
 | 
							if (num_conns > 0)
 | 
				
			||||||
			rate_ctr_add(&rate_ctrs->ctr[MGCP_DLCX_SUCCESS], num_conns);
 | 
								rate_ctr_add(&rate_ctrs->ctr[MGCP_DLCX_SUCCESS], num_conns);
 | 
				
			||||||
@@ -1375,20 +1399,17 @@ static struct msgb *handle_delete_con(struct mgcp_parse_data *p)
 | 
				
			|||||||
	mgcp_format_stats(stats, sizeof(stats), conn->conn);
 | 
						mgcp_format_stats(stats, sizeof(stats), conn->conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* delete connection */
 | 
						/* delete connection */
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:0x%x deleting conn:%s\n",
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG, "DLCX: deleting conn:%s\n",
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
 | 
							 mgcp_conn_dump(conn->conn));
 | 
				
			||||||
	mgcp_conn_free(endp, conn_id);
 | 
						mgcp_conn_free(endp, conn_id);
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "DLCX: endpoint:0x%x connection successfully deleted\n",
 | 
							 "DLCX: connection successfully deleted\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* When all connections are closed, the endpoint will be released
 | 
						/* When all connections are closed, the endpoint will be released
 | 
				
			||||||
	 * in order to be ready to be used by another call. */
 | 
						 * in order to be ready to be used by another call. */
 | 
				
			||||||
	if (llist_count(&endp->conns) <= 0) {
 | 
						if (llist_count(&endp->conns) <= 0) {
 | 
				
			||||||
		mgcp_endp_release(endp);
 | 
							mgcp_endp_release(endp);
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "DLCX: endpoint released\n");
 | 
				
			||||||
		     "DLCX: endpoint:0x%x endpoint released\n",
 | 
					 | 
				
			||||||
		     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->cfg->change_cb)
 | 
						if (p->cfg->change_cb)
 | 
				
			||||||
@@ -1404,8 +1425,7 @@ error3:
 | 
				
			|||||||
	return create_err_response(endp, error_code, "DLCX", p->trans);
 | 
						return create_err_response(endp, error_code, "DLCX", p->trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_silent:
 | 
					out_silent:
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "DLCX: endpoint:0x%x silent exit\n",
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "DLCX: silent exit\n");
 | 
				
			||||||
	     ENDPOINT_NUMBER(endp));
 | 
					 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1448,7 +1468,7 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
 | 
				
			|||||||
	LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
 | 
						LOGP(DLMGCP, LOGL_NOTICE, "RQNT: processing request for notification ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_line(line, p->save) {
 | 
						for_each_line(line, p->save) {
 | 
				
			||||||
		switch (line[0]) {
 | 
							switch (toupper(line[0])) {
 | 
				
			||||||
		case 'S':
 | 
							case 'S':
 | 
				
			||||||
			tone = extract_tone(line);
 | 
								tone = extract_tone(line);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -1531,7 +1551,7 @@ static int free_rate_counter_group(struct rate_ctr_group *rate_ctr_group)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alloc_mgcp_rate_counters(struct mgcp_trunk_config *trunk, void *ctx)
 | 
					static int alloc_mgcp_rate_counters(struct mgcp_trunk_config *trunk, void *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* FIXME: Each new rate counter group requires a unique index. At the
 | 
						/* FIXME: Each new rate counter group requires a unique index. At the
 | 
				
			||||||
	 * moment we generate an index using a counter, but perhaps there is
 | 
						 * moment we generate an index using a counter, but perhaps there is
 | 
				
			||||||
@@ -1543,25 +1563,34 @@ static void alloc_mgcp_rate_counters(struct mgcp_trunk_config *trunk, void *ctx)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (trunk->mgcp_crcx_ctr_group == NULL) {
 | 
						if (trunk->mgcp_crcx_ctr_group == NULL) {
 | 
				
			||||||
		trunk->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
 | 
							trunk->mgcp_crcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!trunk->mgcp_crcx_ctr_group)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_crcx_ctr_group, free_rate_counter_group);
 | 
							talloc_set_destructor(trunk->mgcp_crcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
		crcx_rate_ctr_index++;
 | 
							crcx_rate_ctr_index++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (trunk->mgcp_mdcx_ctr_group == NULL) {
 | 
						if (trunk->mgcp_mdcx_ctr_group == NULL) {
 | 
				
			||||||
		trunk->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
 | 
							trunk->mgcp_mdcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!trunk->mgcp_mdcx_ctr_group)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_mdcx_ctr_group, free_rate_counter_group);
 | 
							talloc_set_destructor(trunk->mgcp_mdcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
		mdcx_rate_ctr_index++;
 | 
							mdcx_rate_ctr_index++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (trunk->mgcp_dlcx_ctr_group == NULL) {
 | 
						if (trunk->mgcp_dlcx_ctr_group == NULL) {
 | 
				
			||||||
		trunk->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
 | 
							trunk->mgcp_dlcx_ctr_group = rate_ctr_group_alloc(ctx, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!trunk->mgcp_dlcx_ctr_group)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
		talloc_set_destructor(trunk->mgcp_dlcx_ctr_group, free_rate_counter_group);
 | 
							talloc_set_destructor(trunk->mgcp_dlcx_ctr_group, free_rate_counter_group);
 | 
				
			||||||
		dlcx_rate_ctr_index++;
 | 
							dlcx_rate_ctr_index++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (trunk->all_rtp_conn_stats == NULL) {
 | 
						if (trunk->all_rtp_conn_stats == NULL) {
 | 
				
			||||||
		trunk->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
 | 
							trunk->all_rtp_conn_stats = rate_ctr_group_alloc(ctx, &all_rtp_conn_rate_ctr_group_desc,
 | 
				
			||||||
								 all_rtp_conn_rate_ctr_index);
 | 
													 all_rtp_conn_rate_ctr_index);
 | 
				
			||||||
 | 
							if (!trunk->all_rtp_conn_stats)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
		talloc_set_destructor(trunk->all_rtp_conn_stats, free_rate_counter_group);
 | 
							talloc_set_destructor(trunk->all_rtp_conn_stats, free_rate_counter_group);
 | 
				
			||||||
		all_rtp_conn_rate_ctr_index++;
 | 
							all_rtp_conn_rate_ctr_index++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! allocate configuration with default values.
 | 
					/*! allocate configuration with default values.
 | 
				
			||||||
@@ -1601,7 +1630,10 @@ struct mgcp_config *mgcp_config_alloc(void)
 | 
				
			|||||||
	cfg->trunk.audio_send_name = 1;
 | 
						cfg->trunk.audio_send_name = 1;
 | 
				
			||||||
	cfg->trunk.omit_rtcp = 0;
 | 
						cfg->trunk.omit_rtcp = 0;
 | 
				
			||||||
	mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
 | 
						mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
	alloc_mgcp_rate_counters(&cfg->trunk, cfg);
 | 
						if (alloc_mgcp_rate_counters(&cfg->trunk, cfg) < 0) {
 | 
				
			||||||
 | 
							talloc_free(cfg);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&cfg->trunks);
 | 
						INIT_LLIST_HEAD(&cfg->trunks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1674,9 +1706,18 @@ int mgcp_endpoints_allocate(struct mgcp_trunk_config *tcfg)
 | 
				
			|||||||
		tcfg->endpoints[i].cfg = tcfg->cfg;
 | 
							tcfg->endpoints[i].cfg = tcfg->cfg;
 | 
				
			||||||
		tcfg->endpoints[i].tcfg = tcfg;
 | 
							tcfg->endpoints[i].tcfg = tcfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* NOTE: Currently all endpoints are of type RTP, this will
 | 
							switch (tcfg->trunk_type) {
 | 
				
			||||||
		 * change when new variations are implemented */
 | 
							case MGCP_TRUNK_VIRTUAL:
 | 
				
			||||||
			tcfg->endpoints[i].type = &ep_typeset.rtp;
 | 
								tcfg->endpoints[i].type = &ep_typeset.rtp;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case MGCP_TRUNK_E1:
 | 
				
			||||||
 | 
								/* FIXME: Implement E1 allocation */
 | 
				
			||||||
 | 
								LOGP(DLMGCP, LOGL_FATAL, "E1 trunks not implemented!\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
 | 
				
			||||||
 | 
									   tcfg->trunk_type, __FILE__, __LINE__);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tcfg->number_endpoints = tcfg->vty_number_endpoints;
 | 
						tcfg->number_endpoints = tcfg->vty_number_endpoints;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,12 +26,15 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_msg.h>
 | 
					#include <osmocom/mgcp/mgcp_msg.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* A struct to store intermediate parsing results. The function
 | 
					/* Two structs to store intermediate parsing results. The function
 | 
				
			||||||
 * mgcp_parse_sdp_data() is using it as temporary storage for parsing the SDP
 | 
					 * mgcp_parse_sdp_data() is using the following two structs as temporary
 | 
				
			||||||
 * codec information. */
 | 
					 * storage for parsing the SDP codec information. */
 | 
				
			||||||
struct sdp_rtp_map {
 | 
					struct sdp_rtp_map {
 | 
				
			||||||
	/* the type */
 | 
						/* the type */
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
@@ -43,6 +46,11 @@ struct sdp_rtp_map {
 | 
				
			|||||||
	int rate;
 | 
						int rate;
 | 
				
			||||||
	int channels;
 | 
						int channels;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					struct sdp_fmtp_param {
 | 
				
			||||||
 | 
						int payload_type;
 | 
				
			||||||
 | 
						struct mgcp_codec_param param;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function to extrapolate missing codec parameters in a codec mao from
 | 
					/* Helper function to extrapolate missing codec parameters in a codec mao from
 | 
				
			||||||
 * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
 | 
					 * an already filled in payload_type, called from: mgcp_parse_sdp_data() */
 | 
				
			||||||
@@ -123,7 +131,8 @@ static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
 | 
				
			|||||||
	char *str;
 | 
						char *str;
 | 
				
			||||||
	char *str_ptr;
 | 
						char *str_ptr;
 | 
				
			||||||
	char *pt_str;
 | 
						char *pt_str;
 | 
				
			||||||
	unsigned int pt;
 | 
						char *pt_end;
 | 
				
			||||||
 | 
						unsigned long int pt;
 | 
				
			||||||
	unsigned int count = 0;
 | 
						unsigned int count = 0;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -148,7 +157,14 @@ static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
 | 
				
			|||||||
		if (!pt_str)
 | 
							if (!pt_str)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pt = atoi(pt_str);
 | 
							errno = 0;
 | 
				
			||||||
 | 
							pt = strtoul(pt_str, &pt_end, 0);
 | 
				
			||||||
 | 
							if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
 | 
				
			||||||
 | 
							    pt_str == pt_end)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Do not allow duplicate payload types */
 | 
							/* Do not allow duplicate payload types */
 | 
				
			||||||
		for (i = 0; i < count; i++)
 | 
							for (i = 0; i < count; i++)
 | 
				
			||||||
@@ -167,6 +183,92 @@ error:
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
 | 
				
			||||||
 | 
					static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *str;
 | 
				
			||||||
 | 
						char *str_ptr;
 | 
				
			||||||
 | 
						char *param_str;
 | 
				
			||||||
 | 
						unsigned int pt;
 | 
				
			||||||
 | 
						unsigned int count = 0;
 | 
				
			||||||
 | 
						char delimiter;
 | 
				
			||||||
 | 
						unsigned int amr_octet_aligned;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(fmtp_param, 0, sizeof(*fmtp_param));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str = talloc_zero_size(ctx, strlen(sdp) + 1);
 | 
				
			||||||
 | 
						str_ptr = str;
 | 
				
			||||||
 | 
						strcpy(str_ptr, sdp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check if the input string begins with an fmtp token */
 | 
				
			||||||
 | 
						str_ptr = strstr(str_ptr, "fmtp:");
 | 
				
			||||||
 | 
						if (!str_ptr)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
						str_ptr += 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Extract payload type */
 | 
				
			||||||
 | 
						if (sscanf(str_ptr, "%u ", &pt) != 1)
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						fmtp_param->payload_type = pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Advance pointer to the beginning of the parameter section and
 | 
				
			||||||
 | 
						 * tokenize string */
 | 
				
			||||||
 | 
						str_ptr = strstr(str_ptr, " ");
 | 
				
			||||||
 | 
						if (!str_ptr)
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						str_ptr++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						param_str = strtok(str_ptr, " ");
 | 
				
			||||||
 | 
						if (!param_str)
 | 
				
			||||||
 | 
							goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							/* Make sure that we don't get trapped in an endless loop */
 | 
				
			||||||
 | 
							if (count > 256)
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Chop off delimiters ';' at the end */
 | 
				
			||||||
 | 
							delimiter = str_ptr[strlen(str_ptr) - 1];
 | 
				
			||||||
 | 
							if (delimiter == ';' || delimiter == ',')
 | 
				
			||||||
 | 
								str_ptr[strlen(str_ptr) - 1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* AMR octet aligned parameter */
 | 
				
			||||||
 | 
							if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
 | 
				
			||||||
 | 
								fmtp_param->param.amr_octet_aligned_present = true;
 | 
				
			||||||
 | 
								fmtp_param->param.amr_octet_aligned = false;
 | 
				
			||||||
 | 
								if (amr_octet_aligned == 1)
 | 
				
			||||||
 | 
									fmtp_param->param.amr_octet_aligned = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							param_str = strtok(NULL, " ");
 | 
				
			||||||
 | 
							if (!param_str)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							count++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
						talloc_free(str);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						talloc_free(str);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Pick optional fmtp parameters by payload type, if there are no fmtp
 | 
				
			||||||
 | 
					 * parameters, a nullpointer is returned */
 | 
				
			||||||
 | 
					static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < fmtp_params_len; i++) {
 | 
				
			||||||
 | 
							if (fmtp_params[i].payload_type == pt)
 | 
				
			||||||
 | 
								return &fmtp_params[i].param;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Analyze SDP input string.
 | 
					/*! Analyze SDP input string.
 | 
				
			||||||
 *  \param[in] endp trunk endpoint.
 | 
					 *  \param[in] endp trunk endpoint.
 | 
				
			||||||
 *  \param[out] conn associated rtp connection.
 | 
					 *  \param[out] conn associated rtp connection.
 | 
				
			||||||
@@ -180,6 +282,9 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
						struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
 | 
				
			||||||
	unsigned int codecs_used = 0;
 | 
						unsigned int codecs_used = 0;
 | 
				
			||||||
 | 
						struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
 | 
				
			||||||
 | 
						unsigned int fmtp_used = 0;
 | 
				
			||||||
 | 
						struct mgcp_codec_param *codec_param;
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
@@ -207,20 +312,31 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			/* skip these SDP attributes */
 | 
								/* skip these SDP attributes */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'a':
 | 
							case 'a':
 | 
				
			||||||
			if (sscanf(line, "a=rtpmap:%d %63s",
 | 
								if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
 | 
				
			||||||
				   &payload, audio_name) == 2) {
 | 
									codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
 | 
				
			||||||
				codecs_update(tmp_ctx, codecs,
 | 
									break;
 | 
				
			||||||
					      codecs_used, payload, audio_name);
 | 
								}
 | 
				
			||||||
			} else
 | 
					
 | 
				
			||||||
			    if (sscanf
 | 
								if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
				
			||||||
				(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
 | 
					 | 
				
			||||||
				if (ptime2 > 0 && ptime2 != ptime)
 | 
									if (ptime2 > 0 && ptime2 != ptime)
 | 
				
			||||||
					rtp->packet_duration_ms = 0;
 | 
										rtp->packet_duration_ms = 0;
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					rtp->packet_duration_ms = ptime;
 | 
										rtp->packet_duration_ms = ptime;
 | 
				
			||||||
			} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
									break;
 | 
				
			||||||
				rtp->maximum_packet_time = ptime2;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
 | 
				
			||||||
 | 
									rtp->maximum_packet_time = ptime2;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (strncmp("a=fmtp:", line, 6) == 0) {
 | 
				
			||||||
 | 
									rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
 | 
				
			||||||
 | 
									if (rc >= 0)
 | 
				
			||||||
 | 
										fmtp_used++;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'm':
 | 
							case 'm':
 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
				
			||||||
@@ -262,14 +378,15 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Store parsed codec information */
 | 
						/* Store parsed codec information */
 | 
				
			||||||
	for (i = 0; i < codecs_used; i++) {
 | 
						for (i = 0; i < codecs_used; i++) {
 | 
				
			||||||
		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line);
 | 
							codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
 | 
				
			||||||
 | 
							rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
 | 
								LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	talloc_free(tmp_ctx);
 | 
						talloc_free(tmp_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
						     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
				
			||||||
	     ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
 | 
						     ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
 | 
				
			||||||
	     rtp->packet_duration_ms);
 | 
						     rtp->packet_duration_ms);
 | 
				
			||||||
@@ -304,15 +421,12 @@ static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Add audio string to sdp payload */
 | 
					/* Add audio strings to sdp payload */
 | 
				
			||||||
static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
 | 
					static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (payload_types_len < 0)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
 | 
						rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
@@ -330,6 +444,64 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Add fmtp strings to sdp payload */
 | 
				
			||||||
 | 
					static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
 | 
				
			||||||
 | 
							    const char *fmtp_extra)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						int fmtp_extra_pt = -1;
 | 
				
			||||||
 | 
						char *fmtp_extra_pars = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When no fmtp parameters ara available but an fmtp extra string
 | 
				
			||||||
 | 
						 * is configured, just add the fmtp extra string */
 | 
				
			||||||
 | 
						if (fmtp_params_len == 0 && fmtp_extra) {
 | 
				
			||||||
 | 
							return msgb_printf(sdp, "%s\r\n", fmtp_extra);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When there is fmtp extra configured we dissect it in order to drop
 | 
				
			||||||
 | 
						 * in the configured extra parameters at the right place when
 | 
				
			||||||
 | 
						 * generating the fmtp strings. */
 | 
				
			||||||
 | 
						if (fmtp_extra) {
 | 
				
			||||||
 | 
							if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
 | 
				
			||||||
 | 
								fmtp_extra_pt = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fmtp_extra_pars = strstr(fmtp_extra, " ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!fmtp_extra_pars)
 | 
				
			||||||
 | 
								fmtp_extra_pars = "";
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								fmtp_extra_pars++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < fmtp_params_len; i++) {
 | 
				
			||||||
 | 
							rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Add amr octet align parameter */
 | 
				
			||||||
 | 
							if (fmtp_params[i].param.amr_octet_aligned_present) {
 | 
				
			||||||
 | 
								if (fmtp_params[i].param.amr_octet_aligned)
 | 
				
			||||||
 | 
									rc = msgb_printf(sdp, " octet-align=1");
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									rc = msgb_printf(sdp, " octet-align=0");
 | 
				
			||||||
 | 
								if (rc < 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Append extra parameters from fmtp extra */
 | 
				
			||||||
 | 
							if (fmtp_params[i].payload_type == fmtp_extra_pt) {
 | 
				
			||||||
 | 
								rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
 | 
				
			||||||
 | 
								if (rc < 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = msgb_printf(sdp, "\r\n", fmtp_params[i].payload_type);
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Generate SDP response string.
 | 
					/*! Generate SDP response string.
 | 
				
			||||||
 *  \param[in] endp trunk endpoint.
 | 
					 *  \param[in] endp trunk endpoint.
 | 
				
			||||||
 *  \param[in] conn associated rtp connection.
 | 
					 *  \param[in] conn associated rtp connection.
 | 
				
			||||||
@@ -340,11 +512,16 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
								    const struct mgcp_conn_rtp *conn, struct msgb *sdp,
 | 
				
			||||||
			    const char *addr)
 | 
								    const char *addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_rtp_codec *codec;
 | 
				
			||||||
	const char *fmtp_extra;
 | 
						const char *fmtp_extra;
 | 
				
			||||||
	const char *audio_name;
 | 
						const char *audio_name;
 | 
				
			||||||
	int payload_type;
 | 
						int payload_type;
 | 
				
			||||||
 | 
						struct sdp_fmtp_param fmtp_param;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	int payload_types[1];
 | 
						int payload_types[1];
 | 
				
			||||||
 | 
						int local_port;
 | 
				
			||||||
 | 
						struct sdp_fmtp_param fmtp_params[1];
 | 
				
			||||||
 | 
					        unsigned int fmtp_params_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
@@ -353,10 +530,12 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
						/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
 | 
				
			||||||
	endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
						endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
 | 
				
			||||||
					      &payload_type, &audio_name,
 | 
										      &codec, &fmtp_extra,
 | 
				
			||||||
					      &fmtp_extra,
 | 
					 | 
				
			||||||
					      (struct mgcp_conn_rtp *)conn);
 | 
										      (struct mgcp_conn_rtp *)conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						audio_name = codec->audio_name;
 | 
				
			||||||
 | 
						payload_type = codec->payload_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = msgb_printf(sdp,
 | 
						rc = msgb_printf(sdp,
 | 
				
			||||||
			 "v=0\r\n"
 | 
								 "v=0\r\n"
 | 
				
			||||||
			 "o=- %s 23 IN IP4 %s\r\n"
 | 
								 "o=- %s 23 IN IP4 %s\r\n"
 | 
				
			||||||
@@ -370,7 +549,11 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	if (payload_type >= 0) {
 | 
						if (payload_type >= 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		payload_types[0] = payload_type;
 | 
							payload_types[0] = payload_type;
 | 
				
			||||||
		rc = add_audio(sdp, payload_types, 1, conn->end.local_port);
 | 
							if (mgcp_conn_rtp_is_osmux(conn))
 | 
				
			||||||
 | 
								local_port = endp->cfg->osmux_port;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								local_port = conn->end.local_port;
 | 
				
			||||||
 | 
							rc = add_audio(sdp, payload_types, 1, local_port);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -380,13 +563,16 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
				goto buffer_too_small;
 | 
									goto buffer_too_small;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (fmtp_extra) {
 | 
							if (codec->param_present) {
 | 
				
			||||||
			rc = msgb_printf(sdp, "%s\r\n", fmtp_extra);
 | 
								fmtp_param.payload_type = payload_type;
 | 
				
			||||||
 | 
								fmtp_param.param = codec->param;
 | 
				
			||||||
 | 
								fmtp_params[0] = fmtp_param;
 | 
				
			||||||
 | 
								fmtp_params_len = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto buffer_too_small;
 | 
								goto buffer_too_small;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
 | 
						if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
 | 
				
			||||||
		rc = msgb_printf(sdp, "a=ptime:%u\r\n",
 | 
							rc = msgb_printf(sdp, "a=ptime:%u\r\n",
 | 
				
			||||||
				 conn->end.packet_duration_ms);
 | 
									 conn->end.packet_duration_ms);
 | 
				
			||||||
@@ -397,6 +583,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
buffer_too_small:
 | 
					buffer_too_small:
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,8 @@
 | 
				
			|||||||
#define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
 | 
					#define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
 | 
				
			||||||
#define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
 | 
					#define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
 | 
				
			||||||
#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
 | 
					#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
 | 
				
			||||||
 | 
					#define RTP_TS101318_RFC5993_CONV_STR "Convert GSM-HR from TS101318 to RFC5993 and vice versa\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mgcp_config *g_cfg = NULL;
 | 
					static struct mgcp_config *g_cfg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,13 +98,17 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		vty_out(vty, "  no rtcp-omit%s", VTY_NEWLINE);
 | 
							vty_out(vty, "  no rtcp-omit%s", VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->trunk.force_constant_ssrc
 | 
						if (g_cfg->trunk.force_constant_ssrc
 | 
				
			||||||
	    || g_cfg->trunk.force_aligned_timing) {
 | 
						    || g_cfg->trunk.force_aligned_timing
 | 
				
			||||||
 | 
						    || g_cfg->trunk.rfc5993_hr_convert) {
 | 
				
			||||||
		vty_out(vty, "  %srtp-patch ssrc%s",
 | 
							vty_out(vty, "  %srtp-patch ssrc%s",
 | 
				
			||||||
			g_cfg->trunk.force_constant_ssrc ? "" : "no ",
 | 
								g_cfg->trunk.force_constant_ssrc ? "" : "no ",
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "  %srtp-patch timestamp%s",
 | 
							vty_out(vty, "  %srtp-patch timestamp%s",
 | 
				
			||||||
			g_cfg->trunk.force_aligned_timing ? "" : "no ",
 | 
								g_cfg->trunk.force_aligned_timing ? "" : "no ",
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
							vty_out(vty, "  %srtp-patch rfc5993hr%s",
 | 
				
			||||||
 | 
								g_cfg->trunk.rfc5993_hr_convert ? "" : "no ",
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
							vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
	if (g_cfg->trunk.audio_payload != -1)
 | 
						if (g_cfg->trunk.audio_payload != -1)
 | 
				
			||||||
@@ -154,6 +160,10 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		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 ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (g_cfg->conn_timeout)
 | 
				
			||||||
 | 
							vty_out(vty, "  conn-timeout %u%s", g_cfg->conn_timeout, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -215,6 +225,13 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp, int epidx
 | 
				
			|||||||
		vty_out(vty, "   CONN: %s%s", mgcp_conn_dump(conn), VTY_NEWLINE);
 | 
							vty_out(vty, "   CONN: %s%s", mgcp_conn_dump(conn), VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (show_stats) {
 | 
							if (show_stats) {
 | 
				
			||||||
 | 
								if (endp->cfg->conn_timeout) {
 | 
				
			||||||
 | 
									struct timeval remaining;
 | 
				
			||||||
 | 
									osmo_timer_remaining(&conn->watchdog, NULL, &remaining);
 | 
				
			||||||
 | 
									vty_out(vty, "   Currently remaining timeout (seconds): %d.%06d%s",
 | 
				
			||||||
 | 
										(int)remaining.tv_sec, (int)remaining.tv_usec, VTY_NEWLINE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* FIXME: Also add verbosity for other
 | 
								/* FIXME: Also add verbosity for other
 | 
				
			||||||
			 * connection types (E1) as soon as
 | 
								 * connection types (E1) as soon as
 | 
				
			||||||
			 * the implementation is available */
 | 
								 * the implementation is available */
 | 
				
			||||||
@@ -280,7 +297,7 @@ DEFUN(show_mcgp, show_mgcp_cmd,
 | 
				
			|||||||
	    dump_trunk(vty, trunk, show_stats);
 | 
						    dump_trunk(vty, trunk, show_stats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->osmux)
 | 
						if (g_cfg->osmux)
 | 
				
			||||||
		vty_out(vty, "Osmux used CID: %d%s", osmux_used_cid(),
 | 
							vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
@@ -711,11 +728,28 @@ DEFUN(cfg_mgcp_no_patch_rtp_ts,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_patch_rtp_rfc5993hr,
 | 
				
			||||||
 | 
					      cfg_mgcp_patch_rtp_rfc5993hr_cmd,
 | 
				
			||||||
 | 
					      "rtp-patch rfc5993hr", RTP_PATCH_STR RTP_TS101318_RFC5993_CONV_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->trunk.rfc5993_hr_convert = true;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_no_patch_rtp_rfc5993hr,
 | 
				
			||||||
 | 
					      cfg_mgcp_no_patch_rtp_rfc5993hr_cmd,
 | 
				
			||||||
 | 
					      "no rtp-patch rfc5993hr", NO_STR RTP_PATCH_STR RTP_TS101318_RFC5993_CONV_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->trunk.rfc5993_hr_convert = false;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgcp_no_patch_rtp,
 | 
					DEFUN(cfg_mgcp_no_patch_rtp,
 | 
				
			||||||
      cfg_mgcp_no_patch_rtp_cmd, "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
					      cfg_mgcp_no_patch_rtp_cmd, "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->trunk.force_constant_ssrc = 0;
 | 
						g_cfg->trunk.force_constant_ssrc = 0;
 | 
				
			||||||
	g_cfg->trunk.force_aligned_timing = 0;
 | 
						g_cfg->trunk.force_aligned_timing = 0;
 | 
				
			||||||
 | 
						g_cfg->trunk.rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -812,13 +846,17 @@ static int config_write_trunk(struct vty *vty)
 | 
				
			|||||||
			vty_out(vty, "  rtcp-omit%s", VTY_NEWLINE);
 | 
								vty_out(vty, "  rtcp-omit%s", VTY_NEWLINE);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			vty_out(vty, "  no rtcp-omit%s", VTY_NEWLINE);
 | 
								vty_out(vty, "  no rtcp-omit%s", VTY_NEWLINE);
 | 
				
			||||||
		if (trunk->force_constant_ssrc || trunk->force_aligned_timing) {
 | 
							if (trunk->force_constant_ssrc || trunk->force_aligned_timing
 | 
				
			||||||
 | 
							    || g_cfg->trunk.rfc5993_hr_convert) {
 | 
				
			||||||
			vty_out(vty, "  %srtp-patch ssrc%s",
 | 
								vty_out(vty, "  %srtp-patch ssrc%s",
 | 
				
			||||||
				trunk->force_constant_ssrc ? "" : "no ",
 | 
									trunk->force_constant_ssrc ? "" : "no ",
 | 
				
			||||||
				VTY_NEWLINE);
 | 
									VTY_NEWLINE);
 | 
				
			||||||
			vty_out(vty, "  %srtp-patch timestamp%s",
 | 
								vty_out(vty, "  %srtp-patch timestamp%s",
 | 
				
			||||||
				trunk->force_aligned_timing ? "" : "no ",
 | 
									trunk->force_aligned_timing ? "" : "no ",
 | 
				
			||||||
				VTY_NEWLINE);
 | 
									VTY_NEWLINE);
 | 
				
			||||||
 | 
								vty_out(vty, "  %srtp-patch rfc5993hr%s",
 | 
				
			||||||
 | 
									trunk->rfc5993_hr_convert ? "" : "no ",
 | 
				
			||||||
 | 
									VTY_NEWLINE);
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
								vty_out(vty, "  no rtp-patch%s", VTY_NEWLINE);
 | 
				
			||||||
		if (trunk->audio_fmtp_extra)
 | 
							if (trunk->audio_fmtp_extra)
 | 
				
			||||||
@@ -984,12 +1022,31 @@ DEFUN(cfg_trunk_no_patch_rtp_ts,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_trunk_patch_rtp_rfc5993hr,
 | 
				
			||||||
 | 
					      cfg_trunk_patch_rtp_rfc5993hr_cmd,
 | 
				
			||||||
 | 
					      "rtp-patch rfc5993hr", RTP_PATCH_STR RTP_TS101318_RFC5993_CONV_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk_config *trunk = vty->index;
 | 
				
			||||||
 | 
						trunk->rfc5993_hr_convert = true;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_trunk_no_patch_rtp_rfc5993hr,
 | 
				
			||||||
 | 
					      cfg_trunk_no_patch_rtp_rfc5993hr_cmd,
 | 
				
			||||||
 | 
					      "no rtp-patch rfc5993hr", NO_STR RTP_PATCH_STR RTP_TS101318_RFC5993_CONV_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mgcp_trunk_config *trunk = vty->index;
 | 
				
			||||||
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_trunk_no_patch_rtp,
 | 
					DEFUN(cfg_trunk_no_patch_rtp,
 | 
				
			||||||
      cfg_trunk_no_patch_rtp_cmd, "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
					      cfg_trunk_no_patch_rtp_cmd, "no rtp-patch", NO_STR RTP_PATCH_STR)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_trunk_config *trunk = vty->index;
 | 
						struct mgcp_trunk_config *trunk = vty->index;
 | 
				
			||||||
	trunk->force_constant_ssrc = 0;
 | 
						trunk->force_constant_ssrc = 0;
 | 
				
			||||||
	trunk->force_aligned_timing = 0;
 | 
						trunk->force_aligned_timing = 0;
 | 
				
			||||||
 | 
						trunk->rfc5993_hr_convert = false;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1248,14 +1305,7 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
	if (strcmp(argv[0], "off") == 0) {
 | 
						if (strcmp(argv[0], "off") == 0) {
 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_OFF;
 | 
							g_cfg->osmux = OSMUX_USAGE_OFF;
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	}
 | 
						} else if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Since OSMUX support is not finished, we do not
 | 
					 | 
				
			||||||
	 * allow to turn it on yet. */
 | 
					 | 
				
			||||||
	vty_out(vty, "OSMUX currently unavailable in this software version.%s", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	return CMD_WARNING;
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	if (strcmp(argv[0], "on") == 0)
 | 
					 | 
				
			||||||
		g_cfg->osmux = OSMUX_USAGE_ON;
 | 
							g_cfg->osmux = 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 = OSMUX_USAGE_ONLY;
 | 
				
			||||||
@@ -1266,7 +1316,7 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_ip,
 | 
					DEFUN(cfg_mgcp_osmux_ip,
 | 
				
			||||||
@@ -1327,6 +1377,19 @@ DEFUN(cfg_mgcp_domain,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_conn_timeout,
 | 
				
			||||||
 | 
					      cfg_mgcp_conn_timeout_cmd,
 | 
				
			||||||
 | 
					      "conn-timeout <0-65534>",
 | 
				
			||||||
 | 
					      "Set a time after which inactive connections (CIs) are closed. Set to 0 to disable timeout. This can be used to"
 | 
				
			||||||
 | 
					      " work around interoperability problems causing connections to stay open forever, and slowly exhausting all"
 | 
				
			||||||
 | 
					      " available ports. Enable keep-alive packets in MGW clients when using this option together with LCLS (OsmoBSC,"
 | 
				
			||||||
 | 
					      " OsmoMSC: 'rtp keep-alive')!\n"
 | 
				
			||||||
 | 
					      "Timeout value (sec.)\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->conn_timeout = strtoul(argv[0], NULL, 10);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mgcp_vty_init(void)
 | 
					int mgcp_vty_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	install_element_ve(&show_mgcp_cmd);
 | 
						install_element_ve(&show_mgcp_cmd);
 | 
				
			||||||
@@ -1377,6 +1440,8 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_rfc5993hr_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_rfc5993hr_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_send_ptime_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_ptime_cmd);
 | 
				
			||||||
@@ -1391,6 +1456,7 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	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);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_conn_timeout_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
 | 
				
			||||||
	install_node(&trunk_node, config_write_trunk);
 | 
						install_node(&trunk_node, config_write_trunk);
 | 
				
			||||||
@@ -1407,6 +1473,8 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd);
 | 
				
			||||||
	install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd);
 | 
				
			||||||
	install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd);
 | 
				
			||||||
 | 
						install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_rfc5993hr_cmd);
 | 
				
			||||||
 | 
						install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_rfc5993hr_cmd);
 | 
				
			||||||
	install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd);
 | 
				
			||||||
	install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd);
 | 
				
			||||||
	install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd);
 | 
						install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -244,6 +244,12 @@ static const struct log_info_cat log_categories[] = {
 | 
				
			|||||||
		  .color = "\033[1;30m",
 | 
							  .color = "\033[1;30m",
 | 
				
			||||||
		  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
		  },
 | 
							  },
 | 
				
			||||||
 | 
						[DIUUP] = {
 | 
				
			||||||
 | 
							  .name = "DIUUP",
 | 
				
			||||||
 | 
							  .description = "IuUP within RTP stream handling",
 | 
				
			||||||
 | 
							  .color = "\033[1;31m",
 | 
				
			||||||
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
 | 
							  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct log_info log_info = {
 | 
					const struct log_info log_info = {
 | 
				
			||||||
@@ -270,9 +276,9 @@ int main(int argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	vty_info.copyright = osmomgw_copyright;
 | 
						vty_info.copyright = osmomgw_copyright;
 | 
				
			||||||
	vty_init(&vty_info);
 | 
						vty_init(&vty_info);
 | 
				
			||||||
	logging_vty_add_cmds(NULL);
 | 
						logging_vty_add_cmds();
 | 
				
			||||||
	osmo_talloc_vty_add_cmds();
 | 
						osmo_talloc_vty_add_cmds();
 | 
				
			||||||
	osmo_stats_vty_add_cmds(&log_info);
 | 
						osmo_stats_vty_add_cmds();
 | 
				
			||||||
	mgcp_vty_init();
 | 
						mgcp_vty_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle_options(argc, argv);
 | 
						handle_options(argc, argv);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
SUBDIRS = \
 | 
					SUBDIRS = \
 | 
				
			||||||
	mgcp_client \
 | 
						mgcp_client \
 | 
				
			||||||
	mgcp \
 | 
						mgcp \
 | 
				
			||||||
 | 
						iuup \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
 | 
					# The `:;' works around a Bash 3.2 bug when the output is not writeable.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										45
									
								
								tests/iuup/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/iuup/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					AM_CPPFLAGS = \
 | 
				
			||||||
 | 
						$(all_includes) \
 | 
				
			||||||
 | 
						-I$(top_srcdir)/include \
 | 
				
			||||||
 | 
						-I$(top_srcdir) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AM_CFLAGS = \
 | 
				
			||||||
 | 
						-Wall \
 | 
				
			||||||
 | 
						-ggdb3 \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOVTY_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMONETIF_CFLAGS) \
 | 
				
			||||||
 | 
						$(COVERAGE_CFLAGS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AM_LDFLAGS = \
 | 
				
			||||||
 | 
						$(COVERAGE_LDFLAGS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXTRA_DIST = \
 | 
				
			||||||
 | 
						iuup_test.ok \
 | 
				
			||||||
 | 
						iuup_test.err \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					noinst_PROGRAMS = \
 | 
				
			||||||
 | 
						iuup_test \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					iuup_test_SOURCES = \
 | 
				
			||||||
 | 
						iuup_test.c \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					iuup_test_LDADD = \
 | 
				
			||||||
 | 
						$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOVTY_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(LIBRARY_DL) \
 | 
				
			||||||
 | 
						$(LIBOSMONETIF_LIBS) \
 | 
				
			||||||
 | 
						-lm  \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update_exp:
 | 
				
			||||||
 | 
						$(builddir)/iuup_test >$(srcdir)/iuup_test.ok 2>$(srcdir)/iuup_test.err
 | 
				
			||||||
							
								
								
									
										156
									
								
								tests/iuup/iuup_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								tests/iuup/iuup_test.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/iuup_cn_node.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/iuup_protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *dump(struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return osmo_hexdump_nospc(msg->data, msg->len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *msgb_from_hex(const char *label, const char *hex)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc_headroom(4096 + OSMO_IUUP_HEADROOM,
 | 
				
			||||||
 | 
										       OSMO_IUUP_HEADROOM, label);
 | 
				
			||||||
 | 
						unsigned char *rc;
 | 
				
			||||||
 | 
						msg->l2h = msg->data;
 | 
				
			||||||
 | 
						rc = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == msg->l2h);
 | 
				
			||||||
 | 
						return msg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *expect_rx_payload = NULL;
 | 
				
			||||||
 | 
					int rx_payload(struct msgb *msg, void *node_priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("rx_payload() invoked by iuup_cn!\n");
 | 
				
			||||||
 | 
						printf("        [IuUP] -RTP->\n");
 | 
				
			||||||
 | 
						printf("%s\n", dump(msg));
 | 
				
			||||||
 | 
						printf("node_priv=%p\n", node_priv);
 | 
				
			||||||
 | 
						if (!expect_rx_payload) {
 | 
				
			||||||
 | 
							printf("ERROR: did not expect rx_payload()\n");
 | 
				
			||||||
 | 
							exit(-1);
 | 
				
			||||||
 | 
						} else if (strcmp(expect_rx_payload, dump(msg))) {
 | 
				
			||||||
 | 
							printf("ERROR: mismatches expected msg %s\n", expect_rx_payload);
 | 
				
			||||||
 | 
							exit(-1);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							printf("ok: matches expected msg\n");
 | 
				
			||||||
 | 
						expect_rx_payload = NULL;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *expect_tx_msg = NULL;
 | 
				
			||||||
 | 
					int tx_msg(struct msgb *msg, void *node_priv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("tx_msg() invoked by iuup_cn!\n");
 | 
				
			||||||
 | 
						printf(" <-PDU- [IuUP]\n");
 | 
				
			||||||
 | 
						printf("%s\n", dump(msg));
 | 
				
			||||||
 | 
						printf("node_priv=%p\n", node_priv);
 | 
				
			||||||
 | 
						if (!expect_tx_msg) {
 | 
				
			||||||
 | 
							printf("ERROR: did not expect tx_msg()\n");
 | 
				
			||||||
 | 
							exit(-1);
 | 
				
			||||||
 | 
						} else if (strcmp(expect_tx_msg, dump(msg))) {
 | 
				
			||||||
 | 
							printf("ERROR: mismatches expected msg %s\n", expect_tx_msg);
 | 
				
			||||||
 | 
							exit(-1);
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							printf("ok: matches expected msg\n");
 | 
				
			||||||
 | 
						expect_tx_msg = NULL;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						printf(" -PDU-> [IuUP]\n");
 | 
				
			||||||
 | 
						printf("%s\n", dump(msg));
 | 
				
			||||||
 | 
						rc = osmo_iuup_cn_rx_pdu(cn, msg);
 | 
				
			||||||
 | 
						printf("rc=%d\n", rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						printf("        [IuUP] <-RTP-\n");
 | 
				
			||||||
 | 
						printf("%s\n", dump(msg));
 | 
				
			||||||
 | 
						rc = osmo_iuup_cn_tx_payload(cn, msg);
 | 
				
			||||||
 | 
						printf("rc=%d\n", rc);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void test_cn_session()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void *node_priv = (void*)0x2342;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_iuup_cn_cfg cfg = {
 | 
				
			||||||
 | 
							.node_priv = node_priv,
 | 
				
			||||||
 | 
							.rx_payload = rx_payload,
 | 
				
			||||||
 | 
							.tx_msg = tx_msg,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_iuup_cn *cn = osmo_iuup_cn_init(ctx, &cfg, __func__);
 | 
				
			||||||
 | 
						OSMO_ASSERT(cn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("\nSend IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack\n");
 | 
				
			||||||
 | 
						expect_tx_msg = "8060dc5219495e3f00010111" /* RTP header */
 | 
				
			||||||
 | 
								"e4002400"; /* IuUP Init Ack */
 | 
				
			||||||
 | 
						rx_pdu(cn,
 | 
				
			||||||
 | 
						       msgb_from_hex("IuUP-Init",
 | 
				
			||||||
 | 
								     "8060dc5219495e3f00010111" /* <- RTP header */
 | 
				
			||||||
 | 
								     "e000df99" /* <- IuUP header */
 | 
				
			||||||
 | 
								     "160051673c01270000820000001710000100" /* IuUP params */));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RTP_HEADER "8060944c6256042c00010102"
 | 
				
			||||||
 | 
					#define IUUP_HEADER "0100e2b3"
 | 
				
			||||||
 | 
					#define RTP_PAYLOAD "6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0"
 | 
				
			||||||
 | 
						printf("\nReceive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet\n");
 | 
				
			||||||
 | 
						printf("i.e. should strip away " IUUP_HEADER "\n");
 | 
				
			||||||
 | 
						expect_rx_payload = RTP_HEADER "f03c" RTP_PAYLOAD;
 | 
				
			||||||
 | 
						rx_pdu(cn,
 | 
				
			||||||
 | 
						       msgb_from_hex("IuUP-Data",
 | 
				
			||||||
 | 
								     RTP_HEADER IUUP_HEADER RTP_PAYLOAD));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("\nTransmit RTP. Expecting tx_msg() with inserted IuUP header\n");
 | 
				
			||||||
 | 
						expect_tx_msg = RTP_HEADER "000002b3" RTP_PAYLOAD;
 | 
				
			||||||
 | 
						tx_payload(cn,
 | 
				
			||||||
 | 
							   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("\nMore RTP, each time the Frame Nr advances, causing a new header CRC.\n");
 | 
				
			||||||
 | 
						expect_tx_msg = RTP_HEADER "0100e2b3" RTP_PAYLOAD;
 | 
				
			||||||
 | 
						tx_payload(cn,
 | 
				
			||||||
 | 
							   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
 | 
				
			||||||
 | 
						expect_tx_msg = RTP_HEADER "02007eb3" RTP_PAYLOAD;
 | 
				
			||||||
 | 
						tx_payload(cn,
 | 
				
			||||||
 | 
							   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
 | 
				
			||||||
 | 
						expect_tx_msg = RTP_HEADER "03009eb3" RTP_PAYLOAD;
 | 
				
			||||||
 | 
						tx_payload(cn,
 | 
				
			||||||
 | 
							   msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("All done.\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct log_info log_info = {
 | 
				
			||||||
 | 
						.cat = log_categories,
 | 
				
			||||||
 | 
						.num_cat = ARRAY_SIZE(log_categories),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ctx = talloc_named_const(NULL, 0, __FILE__);
 | 
				
			||||||
 | 
						void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(ctx, &log_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_cn_session();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(msgb_ctx);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								tests/iuup/iuup_test.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/iuup/iuup_test.err
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										58
									
								
								tests/iuup/iuup_test.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tests/iuup/iuup_test.ok
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					Send IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack
 | 
				
			||||||
 | 
					 -PDU-> [IuUP]
 | 
				
			||||||
 | 
					8060dc5219495e3f00010111e000df99160051673c01270000820000001710000100
 | 
				
			||||||
 | 
					tx_msg() invoked by iuup_cn!
 | 
				
			||||||
 | 
					 <-PDU- [IuUP]
 | 
				
			||||||
 | 
					8060dc5219495e3f00010111e4002400
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Receive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet
 | 
				
			||||||
 | 
					i.e. should strip away 0100e2b3
 | 
				
			||||||
 | 
					 -PDU-> [IuUP]
 | 
				
			||||||
 | 
					8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					rx_payload() invoked by iuup_cn!
 | 
				
			||||||
 | 
					        [IuUP] -RTP->
 | 
				
			||||||
 | 
					8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Transmit RTP. Expecting tx_msg() with inserted IuUP header
 | 
				
			||||||
 | 
					        [IuUP] <-RTP-
 | 
				
			||||||
 | 
					8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					tx_msg() invoked by iuup_cn!
 | 
				
			||||||
 | 
					 <-PDU- [IuUP]
 | 
				
			||||||
 | 
					8060944c6256042c00010102000002b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					More RTP, each time the Frame Nr advances, causing a new header CRC.
 | 
				
			||||||
 | 
					        [IuUP] <-RTP-
 | 
				
			||||||
 | 
					8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					tx_msg() invoked by iuup_cn!
 | 
				
			||||||
 | 
					 <-PDU- [IuUP]
 | 
				
			||||||
 | 
					8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					        [IuUP] <-RTP-
 | 
				
			||||||
 | 
					8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					tx_msg() invoked by iuup_cn!
 | 
				
			||||||
 | 
					 <-PDU- [IuUP]
 | 
				
			||||||
 | 
					8060944c6256042c0001010202007eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					        [IuUP] <-RTP-
 | 
				
			||||||
 | 
					8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					tx_msg() invoked by iuup_cn!
 | 
				
			||||||
 | 
					 <-PDU- [IuUP]
 | 
				
			||||||
 | 
					8060944c6256042c0001010203009eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
 | 
				
			||||||
 | 
					node_priv=0x2342
 | 
				
			||||||
 | 
					ok: matches expected msg
 | 
				
			||||||
 | 
					rc=0
 | 
				
			||||||
 | 
					All done.
 | 
				
			||||||
@@ -28,6 +28,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_internal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/talloc.h>
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
@@ -165,7 +166,7 @@ static void test_strline(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define MDCX4_PT1 \
 | 
					#define MDCX4_PT1 \
 | 
				
			||||||
	"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983217 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendrecv\r" \
 | 
						"M: SENDRECV\r" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20-40, a:AMR, nt:IN\r\n" \
 | 
						"L: p:20-40, a:AMR, nt:IN\r\n" \
 | 
				
			||||||
@@ -208,8 +209,24 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=rtpmap:99 AMR/8000\r\n" \
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_SO \
 | 
					/* Test different upper/lower case in options */
 | 
				
			||||||
 | 
					#define MDCX4_PT4 \
 | 
				
			||||||
	"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983220 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
 | 
						"m: sendrecv\r" \
 | 
				
			||||||
 | 
						"c: 2\r\n" \
 | 
				
			||||||
 | 
						"i: %s\r\n" \
 | 
				
			||||||
 | 
						"l: A:amr, NT:IN\r\n" \
 | 
				
			||||||
 | 
						"\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 4441 RTP/AVP 99\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:99 AMR/8000\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MDCX4_SO \
 | 
				
			||||||
 | 
						"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: sendonly\r" \
 | 
						"M: sendonly\r" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
@@ -224,17 +241,17 @@ static void test_strline(void)
 | 
				
			|||||||
	"a=ptime:40\r\n"
 | 
						"a=ptime:40\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX4_RO \
 | 
					#define MDCX4_RO \
 | 
				
			||||||
	"MDCX 18983221 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: recvonly\r" \
 | 
						"M: recvonly\r" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
	"L: p:20, a:AMR, nt:IN\r\n"
 | 
						"L: p:20, a:AMR, nt:IN\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX_TOO_LONG_CI \
 | 
					#define MDCX_TOO_LONG_CI \
 | 
				
			||||||
	"MDCX 18983222 1@mgw MGCP 1.0\r\n" \
 | 
						"MDCX 18983223 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"I: 123456789012345678901234567890123\n"
 | 
						"I: 123456789012345678901234567890123\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MDCX_TOO_LONG_CI_RET "510 18983222 FAIL\r\n"
 | 
					#define MDCX_TOO_LONG_CI_RET "510 18983223 FAIL\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SHORT2	"CRCX 1"
 | 
					#define SHORT2	"CRCX 1"
 | 
				
			||||||
#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
					#define SHORT2_RET "510 000000 FAIL\r\n"
 | 
				
			||||||
@@ -244,7 +261,7 @@ static void test_strline(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define CRCX \
 | 
					#define CRCX \
 | 
				
			||||||
	"CRCX 2 1@mgw MGCP 1.0\r\n" \
 | 
						"CRCX 2 1@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
	"M: recvonly\r\n" \
 | 
						"m: recvonly\r\n" \
 | 
				
			||||||
	"C: 2\r\n" \
 | 
						"C: 2\r\n" \
 | 
				
			||||||
	"L: p:20\r\n" \
 | 
						"L: p:20\r\n" \
 | 
				
			||||||
	"\r\n" \
 | 
						"\r\n" \
 | 
				
			||||||
@@ -467,6 +484,34 @@ static void test_strline(void)
 | 
				
			|||||||
	"M: recvonly\r\n" \
 | 
						"M: recvonly\r\n" \
 | 
				
			||||||
	"C: 2\r\n"
 | 
						"C: 2\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_AMR_WITH_FMTP \
 | 
				
			||||||
 | 
						"CRCX 2 7@mgw MGCP 1.0\r\n" \
 | 
				
			||||||
 | 
						"M: recvonly\r\n" \
 | 
				
			||||||
 | 
						"C: 2\r\n" \
 | 
				
			||||||
 | 
						"X\r\n" \
 | 
				
			||||||
 | 
						"L: p:20\r\n" \
 | 
				
			||||||
 | 
						"\r\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 123.12.12.123\r\n" \
 | 
				
			||||||
 | 
						"m=audio 5904 RTP/AVP 111\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:111 AMR/8000/1\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n" \
 | 
				
			||||||
 | 
						"a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CRCX_AMR_WITH_FMTP_RET \
 | 
				
			||||||
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
 | 
						"I: %s\r\n" \
 | 
				
			||||||
 | 
						"\r\n" \
 | 
				
			||||||
 | 
						"v=0\r\n" \
 | 
				
			||||||
 | 
						"o=- %s 23 IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"s=-\r\n" \
 | 
				
			||||||
 | 
						"c=IN IP4 0.0.0.0\r\n" \
 | 
				
			||||||
 | 
						"t=0 0\r\n" \
 | 
				
			||||||
 | 
						"m=audio 16012 RTP/AVP 111\r\n" \
 | 
				
			||||||
 | 
						"a=rtpmap:111 AMR/8000/1\r\n" \
 | 
				
			||||||
 | 
						"a=fmtp:111 octet-align=1\r\n" \
 | 
				
			||||||
 | 
						"a=ptime:20\r\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CRCX_NO_LCO_NO_SDP_RET \
 | 
					#define CRCX_NO_LCO_NO_SDP_RET \
 | 
				
			||||||
	"200 2 OK\r\n" \
 | 
						"200 2 OK\r\n" \
 | 
				
			||||||
	"I: %s\r\n" \
 | 
						"I: %s\r\n" \
 | 
				
			||||||
@@ -498,8 +543,9 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
 | 
						{"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
 | 
				
			||||||
	{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
 | 
						{"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
 | 
				
			||||||
	{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
 | 
						{"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
 | 
				
			||||||
	{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983220"), 99},
 | 
						{"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983220"), 99},
 | 
				
			||||||
	{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983221"), PTYPE_IGNORE},
 | 
						{"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983221"), 99},
 | 
				
			||||||
 | 
						{"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983222"), PTYPE_IGNORE},
 | 
				
			||||||
	{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
						{"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
 | 
				
			||||||
	{"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
 | 
						{"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
 | 
				
			||||||
	{"EMPTY", EMPTY, EMPTY_RET},
 | 
						{"EMPTY", EMPTY, EMPTY_RET},
 | 
				
			||||||
@@ -517,6 +563,7 @@ static const struct mgcp_test tests[] = {
 | 
				
			|||||||
	{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
 | 
						{"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
 | 
				
			||||||
	{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
 | 
						{"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
 | 
				
			||||||
	{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
 | 
						{"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
 | 
				
			||||||
 | 
						{"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct mgcp_test retransmit[] = {
 | 
					static const struct mgcp_test retransmit[] = {
 | 
				
			||||||
@@ -970,6 +1017,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
 | 
						struct mgcp_config cfg = {0};
 | 
				
			||||||
	struct mgcp_trunk_config trunk;
 | 
						struct mgcp_trunk_config trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Testing packet loss calculation.\n");
 | 
						printf("Testing packet loss calculation.\n");
 | 
				
			||||||
@@ -977,6 +1025,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
	memset(&endp, 0, sizeof(endp));
 | 
						memset(&endp, 0, sizeof(endp));
 | 
				
			||||||
	memset(&trunk, 0, sizeof(trunk));
 | 
						memset(&trunk, 0, sizeof(trunk));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp.cfg = &cfg;
 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
	trunk.vty_number_endpoints = 1;
 | 
						trunk.vty_number_endpoints = 1;
 | 
				
			||||||
	trunk.endpoints = &endp;
 | 
						trunk.endpoints = &endp;
 | 
				
			||||||
@@ -1189,7 +1238,7 @@ struct rtp_packet_info test_rtp_packets1[] = {
 | 
				
			|||||||
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
					void mgcp_patch_and_count(struct mgcp_endpoint *endp,
 | 
				
			||||||
			  struct mgcp_rtp_state *state,
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
			  struct mgcp_rtp_end *rtp_end,
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
			  struct sockaddr_in *addr, char *data, int len);
 | 
								  struct sockaddr_in *addr, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
					static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1197,10 +1246,10 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	struct mgcp_trunk_config trunk;
 | 
						struct mgcp_trunk_config trunk;
 | 
				
			||||||
	struct mgcp_endpoint endp;
 | 
						struct mgcp_endpoint endp;
 | 
				
			||||||
 | 
						struct mgcp_config cfg = {0};
 | 
				
			||||||
	struct mgcp_rtp_state state;
 | 
						struct mgcp_rtp_state state;
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
	struct sockaddr_in addr = { 0 };
 | 
						struct sockaddr_in addr = { 0 };
 | 
				
			||||||
	char buffer[4096];
 | 
					 | 
				
			||||||
	uint32_t last_ssrc = 0;
 | 
						uint32_t last_ssrc = 0;
 | 
				
			||||||
	uint32_t last_timestamp = 0;
 | 
						uint32_t last_timestamp = 0;
 | 
				
			||||||
	uint32_t last_seqno = 0;
 | 
						uint32_t last_seqno = 0;
 | 
				
			||||||
@@ -1224,6 +1273,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
	state.in_stream.err_ts_ctr = &test_ctr_in;
 | 
						state.in_stream.err_ts_ctr = &test_ctr_in;
 | 
				
			||||||
	state.out_stream.err_ts_ctr = &test_ctr_out;
 | 
						state.out_stream.err_ts_ctr = &test_ctr_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						endp.cfg = &cfg;
 | 
				
			||||||
	endp.type = &ep_typeset.rtp;
 | 
						endp.type = &ep_typeset.rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trunk.vty_number_endpoints = 1;
 | 
						trunk.vty_number_endpoints = 1;
 | 
				
			||||||
@@ -1242,21 +1292,22 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	rtp = &conn->end;
 | 
						rtp = &conn->end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1") == 0);
 | 
						OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
 | 
				
			||||||
	rtp->codec = &rtp->codecs[0];
 | 
						rtp->codec = &rtp->codecs[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
						for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
 | 
				
			||||||
		struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
							struct rtp_packet_info *info = test_rtp_packets1 + i;
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_alloc(4096, __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		force_monotonic_time_us = round(1000000.0 * info->txtime);
 | 
							force_monotonic_time_us = round(1000000.0 * info->txtime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		OSMO_ASSERT(info->len <= sizeof(buffer));
 | 
							OSMO_ASSERT(info->len <= msgb_tailroom(msg));
 | 
				
			||||||
		OSMO_ASSERT(info->len >= 0);
 | 
							OSMO_ASSERT(info->len >= 0);
 | 
				
			||||||
		memmove(buffer, info->data, info->len);
 | 
							msg->l3h = msgb_put(msg, info->len);
 | 
				
			||||||
 | 
							memcpy((char*)msgb_l3(msg), info->data, info->len);
 | 
				
			||||||
		mgcp_rtp_end_config(&endp, 1, rtp);
 | 
							mgcp_rtp_end_config(&endp, 1, rtp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgcp_patch_and_count(&endp, &state, rtp, &addr,
 | 
							mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
 | 
				
			||||||
				     buffer, info->len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (state.out_stream.ssrc != last_ssrc) {
 | 
							if (state.out_stream.ssrc != last_ssrc) {
 | 
				
			||||||
			printf("Output SSRC changed to %08x\n",
 | 
								printf("Output SSRC changed to %08x\n",
 | 
				
			||||||
@@ -1283,6 +1334,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts)
 | 
				
			|||||||
		last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
 | 
							last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
 | 
				
			||||||
		last_timestamp = state.out_stream.last_timestamp;
 | 
							last_timestamp = state.out_stream.last_timestamp;
 | 
				
			||||||
		last_seqno = state.out_stream.last_seq;
 | 
							last_seqno = state.out_stream.last_seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	force_monotonic_time_us = -1;
 | 
						force_monotonic_time_us = -1;
 | 
				
			||||||
@@ -1521,25 +1574,34 @@ static void test_osmux_cid(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int id, i;
 | 
						int id, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(osmux_used_cid() == 0);
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
 | 
				
			||||||
	id = osmux_get_cid();
 | 
					
 | 
				
			||||||
 | 
						id = osmux_cid_pool_get_next();
 | 
				
			||||||
	OSMO_ASSERT(id == 0);
 | 
						OSMO_ASSERT(id == 0);
 | 
				
			||||||
	OSMO_ASSERT(osmux_used_cid() == 1);
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
 | 
				
			||||||
	osmux_put_cid(id);
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(osmux_used_cid() == 0);
 | 
						osmux_cid_pool_get(30);
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
 | 
				
			||||||
 | 
					        osmux_cid_pool_get(30);
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmux_cid_pool_put(id);
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
 | 
				
			||||||
 | 
						osmux_cid_pool_put(30);
 | 
				
			||||||
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 256; ++i) {
 | 
						for (i = 0; i < 256; ++i) {
 | 
				
			||||||
		id = osmux_get_cid();
 | 
							id = osmux_cid_pool_get_next();
 | 
				
			||||||
		OSMO_ASSERT(id == i);
 | 
							OSMO_ASSERT(id == i);
 | 
				
			||||||
		OSMO_ASSERT(osmux_used_cid() == i + 1);
 | 
							OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id = osmux_get_cid();
 | 
						id = osmux_cid_pool_get_next();
 | 
				
			||||||
	OSMO_ASSERT(id == -1);
 | 
						OSMO_ASSERT(id == -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 256; ++i)
 | 
						for (i = 0; i < 256; ++i)
 | 
				
			||||||
		osmux_put_cid(i);
 | 
							osmux_cid_pool_put(i);
 | 
				
			||||||
	OSMO_ASSERT(osmux_used_cid() == 0);
 | 
						OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat log_categories[] = {
 | 
					static const struct log_info_cat log_categories[] = {
 | 
				
			||||||
@@ -1652,98 +1714,335 @@ static void test_check_local_cx_options(void *ctx)
 | 
				
			|||||||
	OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
 | 
						OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_mgcp_codec_pt_translate_pars(struct mgcp_rtp_codec *c)
 | 
					static const struct mgcp_codec_param amr_param_octet_aligned_true = {
 | 
				
			||||||
 | 
						.amr_octet_aligned_present = true,
 | 
				
			||||||
 | 
						.amr_octet_aligned = true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct mgcp_codec_param amr_param_octet_aligned_false = {
 | 
				
			||||||
 | 
						.amr_octet_aligned_present = true,
 | 
				
			||||||
 | 
						.amr_octet_aligned = false,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
 | 
				
			||||||
 | 
						.amr_octet_aligned_present = false,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct testcase_mgcp_codec_pt_translate_codec {
 | 
				
			||||||
 | 
						int payload_type;
 | 
				
			||||||
 | 
						const char *audio_name;
 | 
				
			||||||
 | 
						const struct mgcp_codec_param *param;
 | 
				
			||||||
 | 
						int expect_rc;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct testcase_mgcp_codec_pt_translate_expect {
 | 
				
			||||||
 | 
						bool end;
 | 
				
			||||||
 | 
						int payload_type_map[2];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct testcase_mgcp_codec_pt_translate {
 | 
				
			||||||
 | 
						const char *descr;
 | 
				
			||||||
 | 
						/* two conns on an endpoint, each with N configured codecs */
 | 
				
			||||||
 | 
						struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
 | 
				
			||||||
 | 
						struct testcase_mgcp_codec_pt_translate_expect expect[32];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	c->rate = 8000;
 | 
							.descr = "same order, but differing payload type numbers",
 | 
				
			||||||
	c->channels = 1;
 | 
							.codecs = {
 | 
				
			||||||
	c->frame_duration_num = 23;
 | 
								{
 | 
				
			||||||
	c->frame_duration_den = 42;
 | 
									{ 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
}
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "different order and different payload type numbers",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "both sides have the same payload_type numbers assigned to differing codecs",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 96, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {96, 97}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {97, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "conn0 has no codecs",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									/* no codecs */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "conn1 has no codecs",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									/* no codecs */
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "test AMR with differing octet-aligned settings",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
 | 
									{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 121}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "test AMR with missing octet-aligned settings (defaults to 0)",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "test AMR with NULL param (defaults to 0)",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 122, "AMR/8000", NULL, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08/8000", NULL, },
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000", NULL, },
 | 
				
			||||||
 | 
									{ 96, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 0, "PCMU/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000/1", NULL, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 97, "GSM-HR-08", NULL, },
 | 
				
			||||||
 | 
									{ 0, "PCMU", NULL, },
 | 
				
			||||||
 | 
									{ 96, "AMR", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 96}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {0, 0}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 97} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {123, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.descr = "test whether channel number matching is waterproof",
 | 
				
			||||||
 | 
							.codecs = {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 111, "GSM-HR-08/8000", },
 | 
				
			||||||
 | 
									{ 112, "GSM-HR-08/8000/2", .expect_rc = -22},
 | 
				
			||||||
 | 
									{ 113, "GSM-HR-08/8000/3", .expect_rc = -22},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									{ 122, "GSM-HR-08/8000/2", .expect_rc = -22},
 | 
				
			||||||
 | 
									{ 121, "GSM-HR-08/8000/1", },
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.expect = {
 | 
				
			||||||
 | 
								{ .payload_type_map = {111, 121}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, -EINVAL} },
 | 
				
			||||||
 | 
								{ .payload_type_map = {113, -EINVAL} },
 | 
				
			||||||
 | 
								{ .end = true },
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_mgcp_codec_pt_translate(void)
 | 
					static void test_mgcp_codec_pt_translate(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn_rtp conn_src;
 | 
						int i;
 | 
				
			||||||
	struct mgcp_conn_rtp conn_dst;
 | 
						bool ok = true;
 | 
				
			||||||
	int pt_dst;
 | 
						printf("\nTesting mgcp_codec_pt_translate()\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Setup a realistic set of codec configurations on both
 | 
						for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
 | 
				
			||||||
	 * ends. AMR and HR will use different payload types. PCMU
 | 
							const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
 | 
				
			||||||
	 * must use 0 on both ends since this is not a dynamic payload
 | 
							struct mgcp_conn_rtp conn[2] = {};
 | 
				
			||||||
	 * type */
 | 
							int rc;
 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_src.end.codecs[0]);
 | 
							int conn_i;
 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_dst.end.codecs[0]);
 | 
							int c;
 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_src.end.codecs[1]);
 | 
					 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_dst.end.codecs[1]);
 | 
					 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_src.end.codecs[2]);
 | 
					 | 
				
			||||||
	test_mgcp_codec_pt_translate_pars(&conn_dst.end.codecs[2]);
 | 
					 | 
				
			||||||
	conn_src.end.codecs[0].payload_type = 112;
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[0].payload_type = 96;
 | 
					 | 
				
			||||||
	conn_src.end.codecs[1].payload_type = 0;
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[1].payload_type = 0;
 | 
					 | 
				
			||||||
	conn_src.end.codecs[2].payload_type = 111;
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[2].payload_type = 97;
 | 
					 | 
				
			||||||
	conn_src.end.codecs[0].audio_name = "AMR/8000/1";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[0].audio_name = "AMR/8000/1";
 | 
					 | 
				
			||||||
	conn_src.end.codecs[1].audio_name = "PCMU/8000/1";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[1].audio_name = "PCMU/8000/1";
 | 
					 | 
				
			||||||
	conn_src.end.codecs[2].audio_name = "GSM-HR-08/8000/1";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[2].audio_name = "GSM-HR-08/8000/1";
 | 
					 | 
				
			||||||
	conn_src.end.codecs[0].subtype_name = "AMR";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[0].subtype_name = "AMR";
 | 
					 | 
				
			||||||
	conn_src.end.codecs[1].subtype_name = "PCMU";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[1].subtype_name = "PCMU";
 | 
					 | 
				
			||||||
	conn_src.end.codecs[2].subtype_name = "GSM-HR-08";
 | 
					 | 
				
			||||||
	conn_dst.end.codecs[2].subtype_name = "GSM-HR-08";
 | 
					 | 
				
			||||||
	conn_src.end.codecs_assigned = 3;
 | 
					 | 
				
			||||||
	conn_dst.end.codecs_assigned = 3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We expect the function to find the PT we must use when we send the
 | 
							printf("#%d: %s\n", i, t->descr);
 | 
				
			||||||
	 * packet out to the destination. All we know is the context for both
 | 
					 | 
				
			||||||
	 * connections and the payload type from the source packet */
 | 
					 | 
				
			||||||
	pt_dst =
 | 
					 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
					 | 
				
			||||||
				    conn_src.end.codecs[0].payload_type);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(pt_dst == conn_dst.end.codecs[0].payload_type);
 | 
					 | 
				
			||||||
	pt_dst =
 | 
					 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
					 | 
				
			||||||
				    conn_src.end.codecs[1].payload_type);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(pt_dst == conn_dst.end.codecs[1].payload_type);
 | 
					 | 
				
			||||||
	pt_dst =
 | 
					 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
					 | 
				
			||||||
				    conn_src.end.codecs[2].payload_type);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(pt_dst == conn_dst.end.codecs[2].payload_type);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Try some constellations that must fail */
 | 
							for (conn_i = 0; conn_i < 2; conn_i++) {
 | 
				
			||||||
	pt_dst = mgcp_codec_pt_translate(&conn_src, &conn_dst, 123);
 | 
								printf(" - add codecs on conn%d:\n", conn_i);
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
								for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
 | 
				
			||||||
	conn_src.end.codecs_assigned = 0;
 | 
									const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
 | 
				
			||||||
	conn_dst.end.codecs_assigned = 3;
 | 
									if (!codec->audio_name)
 | 
				
			||||||
	pt_dst =
 | 
										break;
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
					
 | 
				
			||||||
				    conn_src.end.codecs[0].payload_type);
 | 
									rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
					
 | 
				
			||||||
	pt_dst =
 | 
									printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name,
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
									       codec->param ?
 | 
				
			||||||
				    conn_src.end.codecs[1].payload_type);
 | 
										       (codec->param->amr_octet_aligned_present?
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
												(codec->param->amr_octet_aligned ?
 | 
				
			||||||
	pt_dst =
 | 
													" octet-aligned=1" : " octet-aligned=0")
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
												: " octet-aligned=unset")
 | 
				
			||||||
				    conn_src.end.codecs[2].payload_type);
 | 
											: "",
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
											rc);
 | 
				
			||||||
	conn_src.end.codecs_assigned = 3;
 | 
									if (rc != codec->expect_rc) {
 | 
				
			||||||
	conn_dst.end.codecs_assigned = 0;
 | 
										printf("     ERROR: expected rc=%d\n", codec->expect_rc);
 | 
				
			||||||
	pt_dst =
 | 
										ok = false;
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
									}
 | 
				
			||||||
				    conn_src.end.codecs[0].payload_type);
 | 
								}
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
								if (!c)
 | 
				
			||||||
	pt_dst =
 | 
									printf("    (none)\n");
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
							}
 | 
				
			||||||
				    conn_src.end.codecs[1].payload_type);
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
							for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
 | 
				
			||||||
	pt_dst =
 | 
								const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
 | 
				
			||||||
	    mgcp_codec_pt_translate(&conn_src, &conn_dst,
 | 
								int result;
 | 
				
			||||||
				    conn_src.end.codecs[2].payload_type);
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(pt_dst == -EINVAL);
 | 
								if (expect->end)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
 | 
				
			||||||
 | 
								printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
 | 
				
			||||||
 | 
								       expect->payload_type_map[0], result);
 | 
				
			||||||
 | 
								if (result != expect->payload_type_map[1]) {
 | 
				
			||||||
 | 
									printf("     ERROR: expected -> %d\n", expect->payload_type_map[1]);
 | 
				
			||||||
 | 
									ok = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* If the expected result is an error, don't do reverse map test */
 | 
				
			||||||
 | 
								if (expect->payload_type_map[1] < 0)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
 | 
				
			||||||
 | 
								printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
 | 
				
			||||||
 | 
								       expect->payload_type_map[1], result);
 | 
				
			||||||
 | 
								if (result != expect->payload_type_map[0]) {
 | 
				
			||||||
 | 
									printf("     ERROR: expected -> %d\n", expect->payload_type_map[0]);
 | 
				
			||||||
 | 
									ok = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (conn_i = 0; conn_i < 2; conn_i++)
 | 
				
			||||||
 | 
								mgcp_codec_reset_all(&conn[conn_i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ok);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_conn_id_matching()
 | 
					void test_conn_id_matching()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@ Testing CRCX
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
CRCX 2 1@mgw MGCP 1.0
 | 
					CRCX 2 1@mgw MGCP 1.0
 | 
				
			||||||
M: recvonly
 | 
					m: recvonly
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
L: p:20
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,7 +125,7 @@ Testing MDCX4_PT1
 | 
				
			|||||||
Testing MDCX4_PT1
 | 
					Testing MDCX4_PT1
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983217 1@mgw MGCP 1.0
 | 
					MDCX 18983217 1@mgw MGCP 1.0
 | 
				
			||||||
M: SENDRECV
 | 
					M: SENDRECV
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
@@ -193,10 +193,34 @@ Response matches our expectations.
 | 
				
			|||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
Dummy packets: 2
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
 | 
					Testing MDCX4_PT4
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					MDCX 18983220 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					m: sendrecv
 | 
				
			||||||
 | 
					c: 2
 | 
				
			||||||
 | 
					i: %s
 | 
				
			||||||
 | 
					l: A:amr, NT:IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					o=- %s 23 IN IP4 0.0.0.0
 | 
				
			||||||
 | 
					c=IN IP4 0.0.0.0
 | 
				
			||||||
 | 
					t=0 0
 | 
				
			||||||
 | 
					m=audio 4441 RTP/AVP 99
 | 
				
			||||||
 | 
					a=rtpmap:99 AMR/8000
 | 
				
			||||||
 | 
					a=ptime:40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					Dummy packets: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_SO
 | 
					Testing MDCX4_SO
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
@@ -219,7 +243,7 @@ Response matches our expectations.
 | 
				
			|||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response contains a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
================================================
 | 
					================================================
 | 
				
			||||||
Testing MDCX4_RO
 | 
					Testing MDCX4_RO
 | 
				
			||||||
@@ -359,7 +383,7 @@ Testing CRCX
 | 
				
			|||||||
DLCX 7 1@mgw MGCP 1.0
 | 
					DLCX 7 1@mgw MGCP 1.0
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
---------8<---------
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message as statically defined for comparison
 | 
					using message as statically defined for comparison
 | 
				
			||||||
@@ -446,7 +470,7 @@ Dummy packets: 2
 | 
				
			|||||||
m=audio 5904 RTP/AVP 97
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:40
 | 
				
			||||||
---------8<---------
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
checking response:
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
@@ -459,9 +483,33 @@ Response matches our expectations.
 | 
				
			|||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
MDCX 18983223 1@mgw MGCP 1.0
 | 
					MDCX 18983223 1@mgw MGCP 1.0
 | 
				
			||||||
 | 
					I: 123456789012345678901234567890123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
 | 
					using message as statically defined for comparison
 | 
				
			||||||
 | 
					Response matches our expectations.
 | 
				
			||||||
 | 
					(response does not contain a connection id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					================================================
 | 
				
			||||||
 | 
					Testing CRCX
 | 
				
			||||||
 | 
					creating message from statically defined input:
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					CRCX 2 7@mgw MGCP 1.0
 | 
				
			||||||
 | 
					M: recvonly
 | 
				
			||||||
 | 
					C: 2
 | 
				
			||||||
 | 
					X
 | 
				
			||||||
 | 
					L: p:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v=0
 | 
				
			||||||
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
 | 
					m=audio 5904 RTP/AVP 111
 | 
				
			||||||
 | 
					a=rtpmap:111 AMR/8000/1
 | 
				
			||||||
 | 
					a=ptime:20
 | 
				
			||||||
 | 
					a=fmtp:111 mode-change-capability=2; octet-align=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------8<---------
 | 
				
			||||||
 | 
					checking response:
 | 
				
			||||||
using message with patched conn_id for comparison
 | 
					using message with patched conn_id for comparison
 | 
				
			||||||
Response matches our expectations.
 | 
					Response matches our expectations.
 | 
				
			||||||
(response contains a connection id)
 | 
					(response contains a connection id)
 | 
				
			||||||
@@ -478,7 +526,7 @@ Re-transmitting CRCX
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
v=0
 | 
					v=0
 | 
				
			||||||
c=IN IP4 123.12.12.123
 | 
					c=IN IP4 123.12.12.123
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					m=audio 5904 RTP/AVP 97
 | 
				
			||||||
a=rtpmap:97 GSM-EFR/8000
 | 
					a=rtpmap:97 GSM-EFR/8000
 | 
				
			||||||
a=ptime:40
 | 
					a=ptime:40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -590,7 +638,7 @@ Testing packet loss calculation.
 | 
				
			|||||||
Re-transmitting DLCX
 | 
					Re-transmitting DLCX
 | 
				
			||||||
creating message from statically defined input:
 | 
					creating message from statically defined input:
 | 
				
			||||||
---------8<---------
 | 
					---------8<---------
 | 
				
			||||||
I: %s
 | 
					DLCX 7 1@mgw MGCP 1.0
 | 
				
			||||||
I: %s
 | 
					I: %s
 | 
				
			||||||
C: 2
 | 
					C: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1141,7 +1189,7 @@ Testing no rtpmap name
 | 
				
			|||||||
a=rtpmap:4 G723/8000
 | 
					a=rtpmap:4 G723/8000
 | 
				
			||||||
a=rtpmap:96 iLBC/8000
 | 
					a=rtpmap:96 iLBC/8000
 | 
				
			||||||
a=fmtp:96 mode=20
 | 
					a=fmtp:96 mode=20
 | 
				
			||||||
a=fmtp:97 mode=30
 | 
					a=rtpmap:97 iLBC/8000
 | 
				
			||||||
a=fmtp:97 mode=30
 | 
					a=fmtp:97 mode=30
 | 
				
			||||||
a=rtpmap:101 telephone-event/8000
 | 
					a=rtpmap:101 telephone-event/8000
 | 
				
			||||||
a=fmtp:101 0-15
 | 
					a=fmtp:101 0-15
 | 
				
			||||||
@@ -1170,6 +1218,148 @@ p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			|||||||
Testing get_lco_identifier()
 | 
					Testing get_lco_identifier()
 | 
				
			||||||
p:10, a:PCMU -> p:10, a:PCMU
 | 
					p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			||||||
p:10, a:PCMU -> p:10, a:PCMU
 | 
					p:10, a:PCMU -> p:10, a:PCMU
 | 
				
			||||||
 | 
					'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
 | 
				
			||||||
 | 
					'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
 | 
				
			||||||
 | 
					'10,a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
 | 
					'10, a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
 | 
					'10,a: PCMU' -> 'a: PCMU'
 | 
				
			||||||
 | 
					'10 ,a: PCMU' -> 'a: PCMU'
 | 
				
			||||||
 | 
					', a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
 | 
					' a:PCMU' -> 'a:PCMU'
 | 
				
			||||||
 | 
					'' -> '(null)'
 | 
				
			||||||
 | 
					p10, aPCMU -> (null)
 | 
				
			||||||
 | 
					'10,a :PCMU' -> '(null)'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Testing mgcp_codec_pt_translate()
 | 
				
			||||||
 | 
					#0: same order, but differing payload type numbers
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
 | 
					#1: different order and different payload type numbers
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
 | 
					#2: both sides have the same payload_type numbers assigned to differing codecs
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1:  96 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2:  97 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 96) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
 | 
					#3: conn0 has no codecs
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    (none)
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  96 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2:  97 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 | 
					#4: conn1 has no codecs
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    (none)
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 | 
					#5: test AMR with differing octet-aligned settings
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					    1: 121 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 121
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
 | 
				
			||||||
 | 
					#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
 | 
				
			||||||
 | 
					#7: test AMR with NULL param (defaults to 0)
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0: 122 AMR/8000  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
 | 
				
			||||||
 | 
					#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  97 GSM-HR-08/8000  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU/8000  -> rc=0
 | 
				
			||||||
 | 
					    2:  96 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
 | 
					#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 | 
					    0:   0 PCMU/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    1: 111 GSM-HR-08/8000/1  -> rc=0
 | 
				
			||||||
 | 
					    2: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
 | 
					    0:  97 GSM-HR-08  -> rc=0
 | 
				
			||||||
 | 
					    1:   0 PCMU  -> rc=0
 | 
				
			||||||
 | 
					    2:  96 AMR octet-aligned=1  -> rc=0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
 | 
				
			||||||
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
 | 
				
			||||||
 | 
					#10: test whether channel number matching is waterproof
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 GSM-HR-08/8000  -> rc=0
 | 
					    0: 111 GSM-HR-08/8000  -> rc=0
 | 
				
			||||||
    1: 112 GSM-HR-08/8000/2  -> rc=-22
 | 
					    1: 112 GSM-HR-08/8000/2  -> rc=-22
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -157,6 +157,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
		.ptmap[0].pt = 96,
 | 
							.ptmap[0].pt = 96,
 | 
				
			||||||
		.ptmap_len = 1,
 | 
							.ptmap_len = 1,
 | 
				
			||||||
		.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
							.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
 | 
				
			||||||
 | 
							.x_osmo_osmux_cid = -1, /* wildcard */
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp)
 | 
						if (mgcp)
 | 
				
			||||||
@@ -254,6 +255,38 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
	printf("%s\n", (char *)msg->data);
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Generate X-Osmo-Osmux message:\n");
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						mgcp_msg.verb = MGCP_VERB_CRCX;
 | 
				
			||||||
 | 
						mgcp_msg.presence =
 | 
				
			||||||
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
 | 
				
			||||||
 | 
						     | MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Generate X-Osmo-Osmux message (fixed CID 2):\n");
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						mgcp_msg.verb = MGCP_VERB_CRCX;
 | 
				
			||||||
 | 
						mgcp_msg.x_osmo_osmux_cid = 2;
 | 
				
			||||||
 | 
						mgcp_msg.presence =
 | 
				
			||||||
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
 | 
				
			||||||
 | 
						     | MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Generate X-Osmo-Osmux message (MDCX):\n");
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						mgcp_msg.verb = MGCP_VERB_MDCX;
 | 
				
			||||||
 | 
						mgcp_msg.x_osmo_osmux_cid = 2;
 | 
				
			||||||
 | 
						mgcp_msg.presence =
 | 
				
			||||||
 | 
						    (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
 | 
				
			||||||
 | 
						     MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
 | 
				
			||||||
 | 
						     | MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
 | 
				
			||||||
 | 
						msg = mgcp_msg_gen(mgcp, &mgcp_msg);
 | 
				
			||||||
 | 
						printf("%s\n", (char *)msg->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Overfolow test:\n");
 | 
						printf("Overfolow test:\n");
 | 
				
			||||||
	mgcp_msg.verb = MGCP_VERB_MDCX;
 | 
						mgcp_msg.verb = MGCP_VERB_MDCX;
 | 
				
			||||||
	mgcp_msg.presence =
 | 
						mgcp_msg.presence =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,6 +84,30 @@ L: p:20, a:GSM, nt:IN
 | 
				
			|||||||
M: sendrecv
 | 
					M: sendrecv
 | 
				
			||||||
X-Osmo-IGN: C
 | 
					X-Osmo-IGN: C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generate X-Osmo-Osmux message:
 | 
				
			||||||
 | 
					CRCX 13 23@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2f
 | 
				
			||||||
 | 
					I: 11
 | 
				
			||||||
 | 
					L: p:20, a:GSM, nt:IN
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					X-Osmux: *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generate X-Osmo-Osmux message (fixed CID 2):
 | 
				
			||||||
 | 
					CRCX 15 23@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2f
 | 
				
			||||||
 | 
					I: 11
 | 
				
			||||||
 | 
					L: p:20, a:GSM, nt:IN
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					X-Osmux: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Generate X-Osmo-Osmux message (MDCX):
 | 
				
			||||||
 | 
					MDCX 17 23@mgw MGCP 1.0
 | 
				
			||||||
 | 
					C: 2f
 | 
				
			||||||
 | 
					I: 11
 | 
				
			||||||
 | 
					L: p:20, a:GSM, nt:IN
 | 
				
			||||||
 | 
					M: sendrecv
 | 
				
			||||||
 | 
					X-Osmux: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Overfolow test:
 | 
					Overfolow test:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,3 +13,10 @@ AT_KEYWORDS([mgcp])
 | 
				
			|||||||
cat $abs_srcdir/mgcp/mgcp_test.ok > expout
 | 
					cat $abs_srcdir/mgcp/mgcp_test.ok > expout
 | 
				
			||||||
AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore])
 | 
					AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AT_SETUP([iuup])
 | 
				
			||||||
 | 
					AT_KEYWORDS([iuup])
 | 
				
			||||||
 | 
					cat $abs_srcdir/iuup/iuup_test.ok > expout
 | 
				
			||||||
 | 
					cat $abs_srcdir/iuup/iuup_test.err > experr
 | 
				
			||||||
 | 
					AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [], [expout], [experr])
 | 
				
			||||||
 | 
					AT_CLEANUP
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user