mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-04 05:53:26 +00:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			2023q1
			...
			laforge/rt
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b7a0e043b5 | ||
| 
						 | 
					004ea1398a | ||
| 
						 | 
					4f0d72d4c1 | ||
| 
						 | 
					c7d15fb70d | 
							
								
								
									
										445
									
								
								.clang-format
									
									
									
									
									
								
							
							
						
						
									
										445
									
								
								.clang-format
									
									
									
									
									
								
							@@ -64,6 +64,451 @@ DisableFormat: false
 | 
				
			|||||||
ExperimentalAutoDetectBinPacking: false
 | 
					ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
#FixNamespaceComments: false # Unknown to clang-format-4.0
 | 
					#FixNamespaceComments: false # Unknown to clang-format-4.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Taken from:
 | 
				
			||||||
 | 
					#   git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
 | 
				
			||||||
 | 
					#   | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$,  - '\1'," \
 | 
				
			||||||
 | 
					#   | sort | uniq
 | 
				
			||||||
 | 
					ForEachMacros:
 | 
				
			||||||
 | 
					  - 'apei_estatus_for_each_section'
 | 
				
			||||||
 | 
					  - 'ata_for_each_dev'
 | 
				
			||||||
 | 
					  - 'ata_for_each_link'
 | 
				
			||||||
 | 
					  - '__ata_qc_for_each'
 | 
				
			||||||
 | 
					  - 'ata_qc_for_each'
 | 
				
			||||||
 | 
					  - 'ata_qc_for_each_raw'
 | 
				
			||||||
 | 
					  - 'ata_qc_for_each_with_internal'
 | 
				
			||||||
 | 
					  - 'ax25_for_each'
 | 
				
			||||||
 | 
					  - 'ax25_uid_for_each'
 | 
				
			||||||
 | 
					  - '__bio_for_each_bvec'
 | 
				
			||||||
 | 
					  - 'bio_for_each_bvec'
 | 
				
			||||||
 | 
					  - 'bio_for_each_bvec_all'
 | 
				
			||||||
 | 
					  - 'bio_for_each_integrity_vec'
 | 
				
			||||||
 | 
					  - '__bio_for_each_segment'
 | 
				
			||||||
 | 
					  - 'bio_for_each_segment'
 | 
				
			||||||
 | 
					  - 'bio_for_each_segment_all'
 | 
				
			||||||
 | 
					  - 'bio_list_for_each'
 | 
				
			||||||
 | 
					  - 'bip_for_each_vec'
 | 
				
			||||||
 | 
					  - 'bitmap_for_each_clear_region'
 | 
				
			||||||
 | 
					  - 'bitmap_for_each_set_region'
 | 
				
			||||||
 | 
					  - 'blkg_for_each_descendant_post'
 | 
				
			||||||
 | 
					  - 'blkg_for_each_descendant_pre'
 | 
				
			||||||
 | 
					  - 'blk_queue_for_each_rl'
 | 
				
			||||||
 | 
					  - 'bond_for_each_slave'
 | 
				
			||||||
 | 
					  - 'bond_for_each_slave_rcu'
 | 
				
			||||||
 | 
					  - 'bpf_for_each_spilled_reg'
 | 
				
			||||||
 | 
					  - 'btree_for_each_safe128'
 | 
				
			||||||
 | 
					  - 'btree_for_each_safe32'
 | 
				
			||||||
 | 
					  - 'btree_for_each_safe64'
 | 
				
			||||||
 | 
					  - 'btree_for_each_safel'
 | 
				
			||||||
 | 
					  - 'card_for_each_dev'
 | 
				
			||||||
 | 
					  - 'cgroup_taskset_for_each'
 | 
				
			||||||
 | 
					  - 'cgroup_taskset_for_each_leader'
 | 
				
			||||||
 | 
					  - 'cpufreq_for_each_entry'
 | 
				
			||||||
 | 
					  - 'cpufreq_for_each_entry_idx'
 | 
				
			||||||
 | 
					  - 'cpufreq_for_each_valid_entry'
 | 
				
			||||||
 | 
					  - 'cpufreq_for_each_valid_entry_idx'
 | 
				
			||||||
 | 
					  - 'css_for_each_child'
 | 
				
			||||||
 | 
					  - 'css_for_each_descendant_post'
 | 
				
			||||||
 | 
					  - 'css_for_each_descendant_pre'
 | 
				
			||||||
 | 
					  - 'device_for_each_child_node'
 | 
				
			||||||
 | 
					  - 'displayid_iter_for_each'
 | 
				
			||||||
 | 
					  - 'dma_fence_chain_for_each'
 | 
				
			||||||
 | 
					  - 'do_for_each_ftrace_op'
 | 
				
			||||||
 | 
					  - 'drm_atomic_crtc_for_each_plane'
 | 
				
			||||||
 | 
					  - 'drm_atomic_crtc_state_for_each_plane'
 | 
				
			||||||
 | 
					  - 'drm_atomic_crtc_state_for_each_plane_state'
 | 
				
			||||||
 | 
					  - 'drm_atomic_for_each_plane_damage'
 | 
				
			||||||
 | 
					  - 'drm_client_for_each_connector_iter'
 | 
				
			||||||
 | 
					  - 'drm_client_for_each_modeset'
 | 
				
			||||||
 | 
					  - 'drm_connector_for_each_possible_encoder'
 | 
				
			||||||
 | 
					  - 'drm_for_each_bridge_in_chain'
 | 
				
			||||||
 | 
					  - 'drm_for_each_connector_iter'
 | 
				
			||||||
 | 
					  - 'drm_for_each_crtc'
 | 
				
			||||||
 | 
					  - 'drm_for_each_crtc_reverse'
 | 
				
			||||||
 | 
					  - 'drm_for_each_encoder'
 | 
				
			||||||
 | 
					  - 'drm_for_each_encoder_mask'
 | 
				
			||||||
 | 
					  - 'drm_for_each_fb'
 | 
				
			||||||
 | 
					  - 'drm_for_each_legacy_plane'
 | 
				
			||||||
 | 
					  - 'drm_for_each_plane'
 | 
				
			||||||
 | 
					  - 'drm_for_each_plane_mask'
 | 
				
			||||||
 | 
					  - 'drm_for_each_privobj'
 | 
				
			||||||
 | 
					  - 'drm_mm_for_each_hole'
 | 
				
			||||||
 | 
					  - 'drm_mm_for_each_node'
 | 
				
			||||||
 | 
					  - 'drm_mm_for_each_node_in_range'
 | 
				
			||||||
 | 
					  - 'drm_mm_for_each_node_safe'
 | 
				
			||||||
 | 
					  - 'flow_action_for_each'
 | 
				
			||||||
 | 
					  - 'for_each_acpi_dev_match'
 | 
				
			||||||
 | 
					  - 'for_each_active_dev_scope'
 | 
				
			||||||
 | 
					  - 'for_each_active_drhd_unit'
 | 
				
			||||||
 | 
					  - 'for_each_active_iommu'
 | 
				
			||||||
 | 
					  - 'for_each_aggr_pgid'
 | 
				
			||||||
 | 
					  - 'for_each_available_child_of_node'
 | 
				
			||||||
 | 
					  - 'for_each_bio'
 | 
				
			||||||
 | 
					  - 'for_each_board_func_rsrc'
 | 
				
			||||||
 | 
					  - 'for_each_bvec'
 | 
				
			||||||
 | 
					  - 'for_each_card_auxs'
 | 
				
			||||||
 | 
					  - 'for_each_card_auxs_safe'
 | 
				
			||||||
 | 
					  - 'for_each_card_components'
 | 
				
			||||||
 | 
					  - 'for_each_card_dapms'
 | 
				
			||||||
 | 
					  - 'for_each_card_pre_auxs'
 | 
				
			||||||
 | 
					  - 'for_each_card_prelinks'
 | 
				
			||||||
 | 
					  - 'for_each_card_rtds'
 | 
				
			||||||
 | 
					  - 'for_each_card_rtds_safe'
 | 
				
			||||||
 | 
					  - 'for_each_card_widgets'
 | 
				
			||||||
 | 
					  - 'for_each_card_widgets_safe'
 | 
				
			||||||
 | 
					  - 'for_each_cgroup_storage_type'
 | 
				
			||||||
 | 
					  - 'for_each_child_of_node'
 | 
				
			||||||
 | 
					  - 'for_each_clear_bit'
 | 
				
			||||||
 | 
					  - 'for_each_clear_bit_from'
 | 
				
			||||||
 | 
					  - 'for_each_cmsghdr'
 | 
				
			||||||
 | 
					  - 'for_each_compatible_node'
 | 
				
			||||||
 | 
					  - 'for_each_component_dais'
 | 
				
			||||||
 | 
					  - 'for_each_component_dais_safe'
 | 
				
			||||||
 | 
					  - 'for_each_comp_order'
 | 
				
			||||||
 | 
					  - 'for_each_console'
 | 
				
			||||||
 | 
					  - 'for_each_cpu'
 | 
				
			||||||
 | 
					  - 'for_each_cpu_and'
 | 
				
			||||||
 | 
					  - 'for_each_cpu_not'
 | 
				
			||||||
 | 
					  - 'for_each_cpu_wrap'
 | 
				
			||||||
 | 
					  - 'for_each_dapm_widgets'
 | 
				
			||||||
 | 
					  - 'for_each_dev_addr'
 | 
				
			||||||
 | 
					  - 'for_each_dev_scope'
 | 
				
			||||||
 | 
					  - 'for_each_dma_cap_mask'
 | 
				
			||||||
 | 
					  - 'for_each_dpcm_be'
 | 
				
			||||||
 | 
					  - 'for_each_dpcm_be_rollback'
 | 
				
			||||||
 | 
					  - 'for_each_dpcm_be_safe'
 | 
				
			||||||
 | 
					  - 'for_each_dpcm_fe'
 | 
				
			||||||
 | 
					  - 'for_each_drhd_unit'
 | 
				
			||||||
 | 
					  - 'for_each_dss_dev'
 | 
				
			||||||
 | 
					  - 'for_each_dtpm_table'
 | 
				
			||||||
 | 
					  - 'for_each_efi_memory_desc'
 | 
				
			||||||
 | 
					  - 'for_each_efi_memory_desc_in_map'
 | 
				
			||||||
 | 
					  - 'for_each_element'
 | 
				
			||||||
 | 
					  - 'for_each_element_extid'
 | 
				
			||||||
 | 
					  - 'for_each_element_id'
 | 
				
			||||||
 | 
					  - 'for_each_endpoint_of_node'
 | 
				
			||||||
 | 
					  - 'for_each_evictable_lru'
 | 
				
			||||||
 | 
					  - 'for_each_fib6_node_rt_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_fib6_walker_rt'
 | 
				
			||||||
 | 
					  - 'for_each_free_mem_pfn_range_in_zone'
 | 
				
			||||||
 | 
					  - 'for_each_free_mem_pfn_range_in_zone_from'
 | 
				
			||||||
 | 
					  - 'for_each_free_mem_range'
 | 
				
			||||||
 | 
					  - 'for_each_free_mem_range_reverse'
 | 
				
			||||||
 | 
					  - 'for_each_func_rsrc'
 | 
				
			||||||
 | 
					  - 'for_each_hstate'
 | 
				
			||||||
 | 
					  - 'for_each_if'
 | 
				
			||||||
 | 
					  - 'for_each_iommu'
 | 
				
			||||||
 | 
					  - 'for_each_ip_tunnel_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_irq_nr'
 | 
				
			||||||
 | 
					  - 'for_each_link_codecs'
 | 
				
			||||||
 | 
					  - 'for_each_link_cpus'
 | 
				
			||||||
 | 
					  - 'for_each_link_platforms'
 | 
				
			||||||
 | 
					  - 'for_each_lru'
 | 
				
			||||||
 | 
					  - 'for_each_matching_node'
 | 
				
			||||||
 | 
					  - 'for_each_matching_node_and_match'
 | 
				
			||||||
 | 
					  - 'for_each_member'
 | 
				
			||||||
 | 
					  - 'for_each_memcg_cache_index'
 | 
				
			||||||
 | 
					  - 'for_each_mem_pfn_range'
 | 
				
			||||||
 | 
					  - '__for_each_mem_range'
 | 
				
			||||||
 | 
					  - 'for_each_mem_range'
 | 
				
			||||||
 | 
					  - '__for_each_mem_range_rev'
 | 
				
			||||||
 | 
					  - 'for_each_mem_range_rev'
 | 
				
			||||||
 | 
					  - 'for_each_mem_region'
 | 
				
			||||||
 | 
					  - 'for_each_migratetype_order'
 | 
				
			||||||
 | 
					  - 'for_each_msi_entry'
 | 
				
			||||||
 | 
					  - 'for_each_msi_entry_safe'
 | 
				
			||||||
 | 
					  - 'for_each_msi_vector'
 | 
				
			||||||
 | 
					  - 'for_each_net'
 | 
				
			||||||
 | 
					  - 'for_each_net_continue_reverse'
 | 
				
			||||||
 | 
					  - 'for_each_netdev'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_continue'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_continue_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_continue_reverse'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_feature'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_in_bond_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_reverse'
 | 
				
			||||||
 | 
					  - 'for_each_netdev_safe'
 | 
				
			||||||
 | 
					  - 'for_each_net_rcu'
 | 
				
			||||||
 | 
					  - 'for_each_new_connector_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_new_crtc_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_new_mst_mgr_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_new_plane_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_new_private_obj_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_node'
 | 
				
			||||||
 | 
					  - 'for_each_node_by_name'
 | 
				
			||||||
 | 
					  - 'for_each_node_by_type'
 | 
				
			||||||
 | 
					  - 'for_each_node_mask'
 | 
				
			||||||
 | 
					  - 'for_each_node_state'
 | 
				
			||||||
 | 
					  - 'for_each_node_with_cpus'
 | 
				
			||||||
 | 
					  - 'for_each_node_with_property'
 | 
				
			||||||
 | 
					  - 'for_each_nonreserved_multicast_dest_pgid'
 | 
				
			||||||
 | 
					  - 'for_each_of_allnodes'
 | 
				
			||||||
 | 
					  - 'for_each_of_allnodes_from'
 | 
				
			||||||
 | 
					  - 'for_each_of_cpu_node'
 | 
				
			||||||
 | 
					  - 'for_each_of_pci_range'
 | 
				
			||||||
 | 
					  - 'for_each_old_connector_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_old_crtc_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_old_mst_mgr_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_connector_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_crtc_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_mst_mgr_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_plane_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_plane_in_state_reverse'
 | 
				
			||||||
 | 
					  - 'for_each_oldnew_private_obj_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_old_plane_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_old_private_obj_in_state'
 | 
				
			||||||
 | 
					  - 'for_each_online_cpu'
 | 
				
			||||||
 | 
					  - 'for_each_online_node'
 | 
				
			||||||
 | 
					  - 'for_each_online_pgdat'
 | 
				
			||||||
 | 
					  - 'for_each_pci_bridge'
 | 
				
			||||||
 | 
					  - 'for_each_pci_dev'
 | 
				
			||||||
 | 
					  - 'for_each_pci_msi_entry'
 | 
				
			||||||
 | 
					  - 'for_each_pcm_streams'
 | 
				
			||||||
 | 
					  - 'for_each_physmem_range'
 | 
				
			||||||
 | 
					  - 'for_each_populated_zone'
 | 
				
			||||||
 | 
					  - 'for_each_possible_cpu'
 | 
				
			||||||
 | 
					  - 'for_each_present_cpu'
 | 
				
			||||||
 | 
					  - 'for_each_prime_number'
 | 
				
			||||||
 | 
					  - 'for_each_prime_number_from'
 | 
				
			||||||
 | 
					  - 'for_each_process'
 | 
				
			||||||
 | 
					  - 'for_each_process_thread'
 | 
				
			||||||
 | 
					  - 'for_each_prop_codec_conf'
 | 
				
			||||||
 | 
					  - 'for_each_prop_dai_codec'
 | 
				
			||||||
 | 
					  - 'for_each_prop_dai_cpu'
 | 
				
			||||||
 | 
					  - 'for_each_prop_dlc_codecs'
 | 
				
			||||||
 | 
					  - 'for_each_prop_dlc_cpus'
 | 
				
			||||||
 | 
					  - 'for_each_prop_dlc_platforms'
 | 
				
			||||||
 | 
					  - 'for_each_property_of_node'
 | 
				
			||||||
 | 
					  - 'for_each_registered_fb'
 | 
				
			||||||
 | 
					  - 'for_each_requested_gpio'
 | 
				
			||||||
 | 
					  - 'for_each_requested_gpio_in_range'
 | 
				
			||||||
 | 
					  - 'for_each_reserved_mem_range'
 | 
				
			||||||
 | 
					  - 'for_each_reserved_mem_region'
 | 
				
			||||||
 | 
					  - 'for_each_rtd_codec_dais'
 | 
				
			||||||
 | 
					  - 'for_each_rtd_components'
 | 
				
			||||||
 | 
					  - 'for_each_rtd_cpu_dais'
 | 
				
			||||||
 | 
					  - 'for_each_rtd_dais'
 | 
				
			||||||
 | 
					  - 'for_each_set_bit'
 | 
				
			||||||
 | 
					  - 'for_each_set_bit_from'
 | 
				
			||||||
 | 
					  - 'for_each_set_clump8'
 | 
				
			||||||
 | 
					  - 'for_each_sg'
 | 
				
			||||||
 | 
					  - 'for_each_sg_dma_page'
 | 
				
			||||||
 | 
					  - 'for_each_sg_page'
 | 
				
			||||||
 | 
					  - 'for_each_sgtable_dma_page'
 | 
				
			||||||
 | 
					  - 'for_each_sgtable_dma_sg'
 | 
				
			||||||
 | 
					  - 'for_each_sgtable_page'
 | 
				
			||||||
 | 
					  - 'for_each_sgtable_sg'
 | 
				
			||||||
 | 
					  - 'for_each_sibling_event'
 | 
				
			||||||
 | 
					  - 'for_each_subelement'
 | 
				
			||||||
 | 
					  - 'for_each_subelement_extid'
 | 
				
			||||||
 | 
					  - 'for_each_subelement_id'
 | 
				
			||||||
 | 
					  - '__for_each_thread'
 | 
				
			||||||
 | 
					  - 'for_each_thread'
 | 
				
			||||||
 | 
					  - 'for_each_unicast_dest_pgid'
 | 
				
			||||||
 | 
					  - 'for_each_vsi'
 | 
				
			||||||
 | 
					  - 'for_each_wakeup_source'
 | 
				
			||||||
 | 
					  - 'for_each_zone'
 | 
				
			||||||
 | 
					  - 'for_each_zone_zonelist'
 | 
				
			||||||
 | 
					  - 'for_each_zone_zonelist_nodemask'
 | 
				
			||||||
 | 
					  - 'fwnode_for_each_available_child_node'
 | 
				
			||||||
 | 
					  - 'fwnode_for_each_child_node'
 | 
				
			||||||
 | 
					  - 'fwnode_graph_for_each_endpoint'
 | 
				
			||||||
 | 
					  - 'gadget_for_each_ep'
 | 
				
			||||||
 | 
					  - 'genradix_for_each'
 | 
				
			||||||
 | 
					  - 'genradix_for_each_from'
 | 
				
			||||||
 | 
					  - 'hash_for_each'
 | 
				
			||||||
 | 
					  - 'hash_for_each_possible'
 | 
				
			||||||
 | 
					  - 'hash_for_each_possible_rcu'
 | 
				
			||||||
 | 
					  - 'hash_for_each_possible_rcu_notrace'
 | 
				
			||||||
 | 
					  - 'hash_for_each_possible_safe'
 | 
				
			||||||
 | 
					  - 'hash_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'hash_for_each_safe'
 | 
				
			||||||
 | 
					  - 'hctx_for_each_ctx'
 | 
				
			||||||
 | 
					  - 'hlist_bl_for_each_entry'
 | 
				
			||||||
 | 
					  - 'hlist_bl_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_bl_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'hlist_for_each'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_continue'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_continue_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_continue_rcu_bh'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_from'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_from_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_rcu_bh'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_rcu_notrace'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_entry_srcu'
 | 
				
			||||||
 | 
					  - '__hlist_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_for_each_safe'
 | 
				
			||||||
 | 
					  - 'hlist_nulls_for_each_entry'
 | 
				
			||||||
 | 
					  - 'hlist_nulls_for_each_entry_from'
 | 
				
			||||||
 | 
					  - 'hlist_nulls_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'hlist_nulls_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'i3c_bus_for_each_i2cdev'
 | 
				
			||||||
 | 
					  - 'i3c_bus_for_each_i3cdev'
 | 
				
			||||||
 | 
					  - 'ide_host_for_each_port'
 | 
				
			||||||
 | 
					  - 'ide_port_for_each_dev'
 | 
				
			||||||
 | 
					  - 'ide_port_for_each_present_dev'
 | 
				
			||||||
 | 
					  - 'idr_for_each_entry'
 | 
				
			||||||
 | 
					  - 'idr_for_each_entry_continue'
 | 
				
			||||||
 | 
					  - 'idr_for_each_entry_continue_ul'
 | 
				
			||||||
 | 
					  - 'idr_for_each_entry_ul'
 | 
				
			||||||
 | 
					  - 'in_dev_for_each_ifa_rcu'
 | 
				
			||||||
 | 
					  - 'in_dev_for_each_ifa_rtnl'
 | 
				
			||||||
 | 
					  - 'inet_bind_bucket_for_each'
 | 
				
			||||||
 | 
					  - 'inet_lhash2_for_each_icsk_rcu'
 | 
				
			||||||
 | 
					  - 'key_for_each'
 | 
				
			||||||
 | 
					  - 'key_for_each_safe'
 | 
				
			||||||
 | 
					  - 'klp_for_each_func'
 | 
				
			||||||
 | 
					  - 'klp_for_each_func_safe'
 | 
				
			||||||
 | 
					  - 'klp_for_each_func_static'
 | 
				
			||||||
 | 
					  - 'klp_for_each_object'
 | 
				
			||||||
 | 
					  - 'klp_for_each_object_safe'
 | 
				
			||||||
 | 
					  - 'klp_for_each_object_static'
 | 
				
			||||||
 | 
					  - 'kunit_suite_for_each_test_case'
 | 
				
			||||||
 | 
					  - 'kvm_for_each_memslot'
 | 
				
			||||||
 | 
					  - 'kvm_for_each_vcpu'
 | 
				
			||||||
 | 
					  - 'list_for_each'
 | 
				
			||||||
 | 
					  - 'list_for_each_codec'
 | 
				
			||||||
 | 
					  - 'list_for_each_codec_safe'
 | 
				
			||||||
 | 
					  - 'list_for_each_continue'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_continue'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_continue_rcu'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_continue_reverse'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_from'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_from_rcu'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_from_reverse'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_lockless'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_reverse'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_safe_continue'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_safe_from'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_safe_reverse'
 | 
				
			||||||
 | 
					  - 'list_for_each_entry_srcu'
 | 
				
			||||||
 | 
					  - 'list_for_each_prev'
 | 
				
			||||||
 | 
					  - 'list_for_each_prev_safe'
 | 
				
			||||||
 | 
					  - 'list_for_each_safe'
 | 
				
			||||||
 | 
					  - 'llist_for_each'
 | 
				
			||||||
 | 
					  - 'llist_for_each_entry'
 | 
				
			||||||
 | 
					  - 'llist_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'llist_for_each_safe'
 | 
				
			||||||
 | 
					  - 'mci_for_each_dimm'
 | 
				
			||||||
 | 
					  - 'media_device_for_each_entity'
 | 
				
			||||||
 | 
					  - 'media_device_for_each_intf'
 | 
				
			||||||
 | 
					  - 'media_device_for_each_link'
 | 
				
			||||||
 | 
					  - 'media_device_for_each_pad'
 | 
				
			||||||
 | 
					  - 'nanddev_io_for_each_page'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_lower_dev'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_lower_private'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_lower_private_rcu'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_mc_addr'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_uc_addr'
 | 
				
			||||||
 | 
					  - 'netdev_for_each_upper_dev_rcu'
 | 
				
			||||||
 | 
					  - 'netdev_hw_addr_list_for_each'
 | 
				
			||||||
 | 
					  - 'nft_rule_for_each_expr'
 | 
				
			||||||
 | 
					  - 'nla_for_each_attr'
 | 
				
			||||||
 | 
					  - 'nla_for_each_nested'
 | 
				
			||||||
 | 
					  - 'nlmsg_for_each_attr'
 | 
				
			||||||
 | 
					  - 'nlmsg_for_each_msg'
 | 
				
			||||||
 | 
					  - 'nr_neigh_for_each'
 | 
				
			||||||
 | 
					  - 'nr_neigh_for_each_safe'
 | 
				
			||||||
 | 
					  - 'nr_node_for_each'
 | 
				
			||||||
 | 
					  - 'nr_node_for_each_safe'
 | 
				
			||||||
 | 
					  - 'of_for_each_phandle'
 | 
				
			||||||
 | 
					  - 'of_property_for_each_string'
 | 
				
			||||||
 | 
					  - 'of_property_for_each_u32'
 | 
				
			||||||
 | 
					  - 'pci_bus_for_each_resource'
 | 
				
			||||||
 | 
					  - 'pcl_for_each_chunk'
 | 
				
			||||||
 | 
					  - 'pcl_for_each_segment'
 | 
				
			||||||
 | 
					  - 'pcm_for_each_format'
 | 
				
			||||||
 | 
					  - 'ping_portaddr_for_each_entry'
 | 
				
			||||||
 | 
					  - 'plist_for_each'
 | 
				
			||||||
 | 
					  - 'plist_for_each_continue'
 | 
				
			||||||
 | 
					  - 'plist_for_each_entry'
 | 
				
			||||||
 | 
					  - 'plist_for_each_entry_continue'
 | 
				
			||||||
 | 
					  - 'plist_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'plist_for_each_safe'
 | 
				
			||||||
 | 
					  - 'pnp_for_each_card'
 | 
				
			||||||
 | 
					  - 'pnp_for_each_dev'
 | 
				
			||||||
 | 
					  - 'protocol_for_each_card'
 | 
				
			||||||
 | 
					  - 'protocol_for_each_dev'
 | 
				
			||||||
 | 
					  - 'queue_for_each_hw_ctx'
 | 
				
			||||||
 | 
					  - 'radix_tree_for_each_slot'
 | 
				
			||||||
 | 
					  - 'radix_tree_for_each_tagged'
 | 
				
			||||||
 | 
					  - 'rb_for_each'
 | 
				
			||||||
 | 
					  - 'rbtree_postorder_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'rdma_for_each_block'
 | 
				
			||||||
 | 
					  - 'rdma_for_each_port'
 | 
				
			||||||
 | 
					  - 'rdma_umem_for_each_dma_block'
 | 
				
			||||||
 | 
					  - 'resource_list_for_each_entry'
 | 
				
			||||||
 | 
					  - 'resource_list_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'rhl_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'rhl_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'rht_for_each'
 | 
				
			||||||
 | 
					  - 'rht_for_each_entry'
 | 
				
			||||||
 | 
					  - 'rht_for_each_entry_from'
 | 
				
			||||||
 | 
					  - 'rht_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'rht_for_each_entry_rcu_from'
 | 
				
			||||||
 | 
					  - 'rht_for_each_entry_safe'
 | 
				
			||||||
 | 
					  - 'rht_for_each_from'
 | 
				
			||||||
 | 
					  - 'rht_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'rht_for_each_rcu_from'
 | 
				
			||||||
 | 
					  - '__rq_for_each_bio'
 | 
				
			||||||
 | 
					  - 'rq_for_each_bvec'
 | 
				
			||||||
 | 
					  - 'rq_for_each_segment'
 | 
				
			||||||
 | 
					  - 'scsi_for_each_prot_sg'
 | 
				
			||||||
 | 
					  - 'scsi_for_each_sg'
 | 
				
			||||||
 | 
					  - 'sctp_for_each_hentry'
 | 
				
			||||||
 | 
					  - 'sctp_skb_for_each'
 | 
				
			||||||
 | 
					  - 'shdma_for_each_chan'
 | 
				
			||||||
 | 
					  - '__shost_for_each_device'
 | 
				
			||||||
 | 
					  - 'shost_for_each_device'
 | 
				
			||||||
 | 
					  - 'sk_for_each'
 | 
				
			||||||
 | 
					  - 'sk_for_each_bound'
 | 
				
			||||||
 | 
					  - 'sk_for_each_entry_offset_rcu'
 | 
				
			||||||
 | 
					  - 'sk_for_each_from'
 | 
				
			||||||
 | 
					  - 'sk_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'sk_for_each_safe'
 | 
				
			||||||
 | 
					  - 'sk_nulls_for_each'
 | 
				
			||||||
 | 
					  - 'sk_nulls_for_each_from'
 | 
				
			||||||
 | 
					  - 'sk_nulls_for_each_rcu'
 | 
				
			||||||
 | 
					  - 'snd_array_for_each'
 | 
				
			||||||
 | 
					  - 'snd_pcm_group_for_each_entry'
 | 
				
			||||||
 | 
					  - 'snd_soc_dapm_widget_for_each_path'
 | 
				
			||||||
 | 
					  - 'snd_soc_dapm_widget_for_each_path_safe'
 | 
				
			||||||
 | 
					  - 'snd_soc_dapm_widget_for_each_sink_path'
 | 
				
			||||||
 | 
					  - 'snd_soc_dapm_widget_for_each_source_path'
 | 
				
			||||||
 | 
					  - 'tb_property_for_each'
 | 
				
			||||||
 | 
					  - 'tcf_exts_for_each_action'
 | 
				
			||||||
 | 
					  - 'udp_portaddr_for_each_entry'
 | 
				
			||||||
 | 
					  - 'udp_portaddr_for_each_entry_rcu'
 | 
				
			||||||
 | 
					  - 'usb_hub_for_each_child'
 | 
				
			||||||
 | 
					  - 'v4l2_device_for_each_subdev'
 | 
				
			||||||
 | 
					  - 'v4l2_m2m_for_each_dst_buf'
 | 
				
			||||||
 | 
					  - 'v4l2_m2m_for_each_dst_buf_safe'
 | 
				
			||||||
 | 
					  - 'v4l2_m2m_for_each_src_buf'
 | 
				
			||||||
 | 
					  - 'v4l2_m2m_for_each_src_buf_safe'
 | 
				
			||||||
 | 
					  - 'virtio_device_for_each_vq'
 | 
				
			||||||
 | 
					  - 'while_for_each_ftrace_op'
 | 
				
			||||||
 | 
					  - 'xa_for_each'
 | 
				
			||||||
 | 
					  - 'xa_for_each_marked'
 | 
				
			||||||
 | 
					  - 'xa_for_each_range'
 | 
				
			||||||
 | 
					  - 'xa_for_each_start'
 | 
				
			||||||
 | 
					  - 'xas_for_each'
 | 
				
			||||||
 | 
					  - 'xas_for_each_conflict'
 | 
				
			||||||
 | 
					  - 'xas_for_each_marked'
 | 
				
			||||||
 | 
					  - 'xbc_array_for_each_value'
 | 
				
			||||||
 | 
					  - 'xbc_for_each_key_value'
 | 
				
			||||||
 | 
					  - 'xbc_node_for_each_array_value'
 | 
				
			||||||
 | 
					  - 'xbc_node_for_each_child'
 | 
				
			||||||
 | 
					  - 'xbc_node_for_each_key_value'
 | 
				
			||||||
 | 
					  - 'zorro_for_each_dev'
 | 
				
			||||||
 | 
					  - 'for_each_line'
 | 
				
			||||||
 | 
					  - 'for_each_non_empty_line'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
 | 
					#IncludeBlocks: Preserve # Unknown to clang-format-5.0
 | 
				
			||||||
IncludeCategories:
 | 
					IncludeCategories:
 | 
				
			||||||
  - Regex: '.*'
 | 
					  - Regex: '.*'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
To run the configuration parsing and output (VTY) test suite, first install
 | 
					To run the configuration parsing and output (VTY) test suite, first install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests
 | 
					  git://git.osmocom.org/python/osmo-python-tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
and pass the following configure options here:
 | 
					and pass the following configure options here:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,5 @@
 | 
				
			|||||||
# If any interfaces have been removed or changed since the last public release, a=0.
 | 
					# If any interfaces have been removed or changed since the last public release, a=0.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#library		what		description / commit summary line
 | 
					#library		what		description / commit summary line
 | 
				
			||||||
libosmo-netif           >1.2.0          OSMUX_DEFAULT_PORT, osmux_xfrm_output_*, osmux_xfrm_input_*
 | 
					update dependency to libosmocore > 1.5.1 for our use of osmo_sock_set_dscp()
 | 
				
			||||||
libosmocore             >1.7.0          osmo_sockaddr_is_any()
 | 
					libosmo-mgcp-client  struct mgcp_client_conf ABI breackage
 | 
				
			||||||
libmgcp-client          NEW APIs        mgcp_client_pool_member_...(), mgcp_client_pool_config_write()
 | 
					 | 
				
			||||||
							
								
								
									
										17
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								configure.ac
									
									
									
									
									
								
							@@ -44,13 +44,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
 | 
				
			|||||||
AC_SUBST(LIBRARY_DLSYM)
 | 
					AC_SUBST(LIBRARY_DLSYM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.2.0)
 | 
					PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
 | 
				
			||||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.3.0)
 | 
					PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.1.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CFLAGS="$CFLAGS -pthread"
 | 
					CFLAGS="$CFLAGS -pthread"
 | 
				
			||||||
LDFLAGS="$LDFLAGS -pthread"
 | 
					LDFLAGS="$LDFLAGS -pthread"
 | 
				
			||||||
@@ -79,7 +79,6 @@ AC_ARG_ENABLE(werror,
 | 
				
			|||||||
if test x"$werror" = x"yes"
 | 
					if test x"$werror" = x"yes"
 | 
				
			||||||
then
 | 
					then
 | 
				
			||||||
	WERROR_FLAGS="-Werror"
 | 
						WERROR_FLAGS="-Werror"
 | 
				
			||||||
	WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
 | 
					 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
						WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
				
			||||||
	WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
						WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
				
			||||||
	CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
						CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
				
			||||||
@@ -113,7 +112,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
 | 
				
			|||||||
	AM_PATH_PYTHON
 | 
						AM_PATH_PYTHON
 | 
				
			||||||
	AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
 | 
						AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
 | 
				
			||||||
	 if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
 | 
						 if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
 | 
				
			||||||
		AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
 | 
							AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
					AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,10 @@
 | 
				
			|||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 * GNU General Public License for more details.
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License along
 | 
				
			||||||
 | 
					 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
				
			||||||
 | 
					 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,30 +29,30 @@ BuildRequires:  pkgconfig >= 0.20
 | 
				
			|||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
BuildRequires:  systemd-rpm-macros
 | 
					BuildRequires:  systemd-rpm-macros
 | 
				
			||||||
%endif
 | 
					%endif
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmo-netif) >= 1.2.0
 | 
					BuildRequires:  pkgconfig(libosmo-netif) >= 1.1.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocore) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmocore) >= 1.5.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmoctrl) >= 1.5.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmogsm) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmogsm) >= 1.5.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmovty) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmovty) >= 1.5.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmocoding) >= 1.7.0
 | 
					BuildRequires:  pkgconfig(libosmocoding) >= 1.5.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmoabis) >= 1.3.0
 | 
					BuildRequires:  pkgconfig(libosmoabis) >= 1.1.0
 | 
				
			||||||
BuildRequires:  pkgconfig(libosmotrau) >= 1.3.0
 | 
					BuildRequires:  pkgconfig(libosmotrau) >= 1.1.0
 | 
				
			||||||
%{?systemd_requires}
 | 
					%{?systemd_requires}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description
 | 
					%description
 | 
				
			||||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
					OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client9
 | 
					%package -n libosmo-mgcp-client8
 | 
				
			||||||
Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          System/Libraries
 | 
					Group:          System/Libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client9
 | 
					%description -n libosmo-mgcp-client8
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client library.
 | 
					Osmocom's Media Gateway Control Protocol client library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%package -n libosmo-mgcp-client-devel
 | 
					%package -n libosmo-mgcp-client-devel
 | 
				
			||||||
Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
					Summary:        Development files for Osmocom's Media Gateway Control Protocol client library
 | 
				
			||||||
Group:          Development/Libraries/C and C++
 | 
					Group:          Development/Libraries/C and C++
 | 
				
			||||||
Requires:       libosmo-mgcp-client9 = %{version}
 | 
					Requires:       libosmo-mgcp-client8 = %{version}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%description -n libosmo-mgcp-client-devel
 | 
					%description -n libosmo-mgcp-client-devel
 | 
				
			||||||
Osmocom's Media Gateway Control Protocol client librarary.
 | 
					Osmocom's Media Gateway Control Protocol client librarary.
 | 
				
			||||||
@@ -90,8 +90,8 @@ find %{buildroot} -type f -name "*.la" -delete -print
 | 
				
			|||||||
%check
 | 
					%check
 | 
				
			||||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
					make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%post   -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
					%post   -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
				
			||||||
%postun -n libosmo-mgcp-client9 -p /sbin/ldconfig
 | 
					%postun -n libosmo-mgcp-client8 -p /sbin/ldconfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%if 0%{?suse_version}
 | 
					%if 0%{?suse_version}
 | 
				
			||||||
%preun
 | 
					%preun
 | 
				
			||||||
@@ -119,8 +119,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
				
			|||||||
%dir %{_sysconfdir}/osmocom
 | 
					%dir %{_sysconfdir}/osmocom
 | 
				
			||||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
					%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client9
 | 
					%files -n libosmo-mgcp-client8
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so.9*
 | 
					%{_libdir}/libosmo-mgcp-client.so.8*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%files -n libosmo-mgcp-client-devel
 | 
					%files -n libosmo-mgcp-client-devel
 | 
				
			||||||
%{_libdir}/libosmo-mgcp-client.so
 | 
					%{_libdir}/libosmo-mgcp-client.so
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								contrib/rtp-load-gen/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								contrib/rtp-load-gen/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					CFLAGS=-g -Wall $(shell pkg-config --cflags libosmocore libosmoctrl libosmo-netif liburing)
 | 
				
			||||||
 | 
					LIBS=-lpthread $(shell pkg-config --libs libosmocore libosmoctrl libosmo-netif liburing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rtp-load-gen: rtp-load-gen.o rtp_provider.o rtp_provider_static.o ctrl_if.o
 | 
				
			||||||
 | 
						$(CC) -o $@ $^ $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%.o: %.c
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) -o $@ -c $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						@rm rtp-load-gen *.o
 | 
				
			||||||
							
								
								
									
										214
									
								
								contrib/rtp-load-gen/ctrl_if.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								contrib/rtp-load-gen/ctrl_if.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,214 @@
 | 
				
			|||||||
 | 
					/* CTRL interface of rtpsource program
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 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 General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_cmd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "rtp_provider.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rtpsim_connection *find_connection_by_cname(const char *cname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc;
 | 
				
			||||||
 | 
						struct rtpsim_instance *ri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pthread_rwlock_rdlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
						llist_for_each_entry(ri, &g_rtpsim->instances, list) {
 | 
				
			||||||
 | 
							rtpc = rtpsim_conn_find(ri, cname);
 | 
				
			||||||
 | 
							if (rtpc) {
 | 
				
			||||||
 | 
								pthread_rwlock_unlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
								return rtpc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_rwlock_unlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rtpsim_connection *create_connection(const char *cname, enum codec_type codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc;
 | 
				
			||||||
 | 
						struct rtpsim_instance *ri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pthread_rwlock_rdlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
						llist_for_each_entry(ri, &g_rtpsim->instances, list) {
 | 
				
			||||||
 | 
							rtpc = rtpsim_conn_reserve(ri, cname, codec);
 | 
				
			||||||
 | 
							if (rtpc) {
 | 
				
			||||||
 | 
								pthread_rwlock_unlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
								return rtpc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_rwlock_unlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int connect_connection(struct rtpsim_connection *rtpc, const char *remote_host,
 | 
				
			||||||
 | 
								      uint16_t remote_port, uint8_t pt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_sockaddr_str_from_str(&rtpc->cfg.remote, remote_host, remote_port);
 | 
				
			||||||
 | 
						rtpc->cfg.pt = pt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rtpsim_conn_connect(rtpc);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rtpsim_conn_start(rtpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int delete_connection(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtpsim_conn_stop(rtpc);
 | 
				
			||||||
 | 
						rtpsim_conn_unreserve(rtpc);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CTRL_CMD_DEFINE_WO_NOVRF(rtp_create, "rtp_create");
 | 
				
			||||||
 | 
					static int set_rtp_create(struct ctrl_cmd *cmd, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *conn;
 | 
				
			||||||
 | 
						const char *cname, *codec_str;
 | 
				
			||||||
 | 
						char *tmp, *saveptr;
 | 
				
			||||||
 | 
						enum codec_type codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = talloc_strdup(cmd, cmd->value);
 | 
				
			||||||
 | 
						OSMO_ASSERT(tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cname = strtok_r(tmp, ",", &saveptr);
 | 
				
			||||||
 | 
						codec_str = strtok_r(NULL, ",", &saveptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cname || !codec_str) {
 | 
				
			||||||
 | 
							cmd->reply = "Format is cname,codec";
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (find_connection_by_cname(cname)) {
 | 
				
			||||||
 | 
							cmd->reply = "Connection already exists for cname";
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						codec = get_string_value(codec_type_names, codec_str);
 | 
				
			||||||
 | 
						if (codec < 0) {
 | 
				
			||||||
 | 
							cmd->reply = "Invalid codec name (try GSM_FR, GSM_EFR etc.)";
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = create_connection(cname, codec);
 | 
				
			||||||
 | 
						if (!conn) {
 | 
				
			||||||
 | 
							cmd->reply = "Error creating RTP connection";
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Respond */
 | 
				
			||||||
 | 
						cmd->reply = talloc_asprintf(cmd, "%s,%s,%d", conn->cname, conn->cfg.local.ip, conn->cfg.local.port);
 | 
				
			||||||
 | 
						talloc_free(tmp);
 | 
				
			||||||
 | 
						return CTRL_CMD_REPLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						talloc_free(tmp);
 | 
				
			||||||
 | 
						return CTRL_CMD_ERROR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CTRL_CMD_DEFINE_WO_NOVRF(rtp_connect, "rtp_connect");
 | 
				
			||||||
 | 
					static int set_rtp_connect(struct ctrl_cmd *cmd, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *conn;
 | 
				
			||||||
 | 
						const char *cname, *remote_host, *remote_port, *pt;
 | 
				
			||||||
 | 
						char *tmp, *saveptr;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = talloc_strdup(cmd, cmd->value);
 | 
				
			||||||
 | 
						OSMO_ASSERT(tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: parse command */
 | 
				
			||||||
 | 
						cname = strtok_r(tmp, ",", &saveptr);
 | 
				
			||||||
 | 
						remote_host = strtok_r(NULL, ",", &saveptr);
 | 
				
			||||||
 | 
						remote_port = strtok_r(NULL, ",", &saveptr);
 | 
				
			||||||
 | 
						pt = strtok_r(NULL, ",", &saveptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cname || !remote_host || !remote_port || !pt) {
 | 
				
			||||||
 | 
							cmd->reply = "Format is cname,remote_host,remote_port,pt";
 | 
				
			||||||
 | 
							talloc_free(tmp);
 | 
				
			||||||
 | 
							return CTRL_CMD_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = find_connection_by_cname(cname);
 | 
				
			||||||
 | 
						if (!conn) {
 | 
				
			||||||
 | 
							cmd->reply = "Error finding RTP connection for connect";
 | 
				
			||||||
 | 
							talloc_free(tmp);
 | 
				
			||||||
 | 
							return CTRL_CMD_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = connect_connection(conn, remote_host, atoi(remote_port), atoi(pt));
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							cmd->reply = "Error binding RTP connection";
 | 
				
			||||||
 | 
							talloc_free(tmp);
 | 
				
			||||||
 | 
							return CTRL_CMD_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Respond */
 | 
				
			||||||
 | 
						talloc_free(tmp);
 | 
				
			||||||
 | 
						cmd->reply = talloc_asprintf(cmd, "%s,%s,%d,%d", conn->cname, conn->cfg.remote.ip,
 | 
				
			||||||
 | 
										conn->cfg.remote.port, conn->cfg.pt);
 | 
				
			||||||
 | 
						return CTRL_CMD_REPLY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CTRL_CMD_DEFINE_WO_NOVRF(rtp_delete, "rtp_delete");
 | 
				
			||||||
 | 
					static int set_rtp_delete(struct ctrl_cmd *cmd, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *conn;
 | 
				
			||||||
 | 
						const char *cname = cmd->value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = find_connection_by_cname(cname);
 | 
				
			||||||
 | 
						if (!conn) {
 | 
				
			||||||
 | 
							cmd->reply = "Error finding RTP connection for delete";
 | 
				
			||||||
 | 
							return CTRL_CMD_ERROR;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cmd->reply = talloc_asprintf(cmd, "%s", conn->cname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						delete_connection(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Respond */
 | 
				
			||||||
 | 
						return CTRL_CMD_REPLY;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rtpsource_ctrl_cmds_install(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_create);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_connect);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rtp_delete);
 | 
				
			||||||
 | 
						if (rc)
 | 
				
			||||||
 | 
							goto end;
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										112
									
								
								contrib/rtp-load-gen/internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								contrib/rtp-load-gen/internal.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <liburing.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider_instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* configuration of one RTP connection/socket */
 | 
				
			||||||
 | 
					struct rtpsim_connection_cfg {
 | 
				
			||||||
 | 
						struct osmo_sockaddr_str local;
 | 
				
			||||||
 | 
						struct osmo_sockaddr_str remote;
 | 
				
			||||||
 | 
						uint8_t pt;
 | 
				
			||||||
 | 
						uint32_t ssrc;
 | 
				
			||||||
 | 
						uint32_t duration;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TX side state of RTP connection/socket */
 | 
				
			||||||
 | 
					struct rtpsim_connection_tx {
 | 
				
			||||||
 | 
						bool enabled;
 | 
				
			||||||
 | 
						uint32_t timestamp;
 | 
				
			||||||
 | 
						uint16_t seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct rtp_provider_instance *rtp_prov_inst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* transmit buffer for outgoing messages */
 | 
				
			||||||
 | 
						uint8_t *buf;
 | 
				
			||||||
 | 
						/* used part of buffer */
 | 
				
			||||||
 | 
						size_t buf_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* RX side state of RTP connection/socket */
 | 
				
			||||||
 | 
					struct rtpsim_connection_rx {
 | 
				
			||||||
 | 
						bool enabled;
 | 
				
			||||||
 | 
						/* receive buffer for incoming messages */
 | 
				
			||||||
 | 
						uint8_t *buf;
 | 
				
			||||||
 | 
						/* used length of buffer */
 | 
				
			||||||
 | 
						size_t buf_len;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* One RTP connection/socket */
 | 
				
			||||||
 | 
					struct rtpsim_connection {
 | 
				
			||||||
 | 
						/* index in rtp_instance.connections */
 | 
				
			||||||
 | 
						unsigned int idx;
 | 
				
			||||||
 | 
						/* back-pointer */
 | 
				
			||||||
 | 
						struct rtpsim_instance *inst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct rtpsim_connection_cfg cfg;
 | 
				
			||||||
 | 
						struct rtpsim_connection_tx tx;
 | 
				
			||||||
 | 
						struct rtpsim_connection_rx rx;
 | 
				
			||||||
 | 
						struct rate_ctr_group *ctrg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* socket file descriptor */
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						char *cname;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_instance_cfg {
 | 
				
			||||||
 | 
						int num;
 | 
				
			||||||
 | 
						uint16_t base_port;
 | 
				
			||||||
 | 
						unsigned int num_flows;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* one instance of the RTP simulator; typically one per worker thread */
 | 
				
			||||||
 | 
					struct rtpsim_instance {
 | 
				
			||||||
 | 
						/* element in application global list of instances */
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
						struct rtpsim_instance_cfg cfg;
 | 
				
			||||||
 | 
						/* per-instance io_uring */
 | 
				
			||||||
 | 
						struct io_uring ring;
 | 
				
			||||||
 | 
						/* per-instance timerfd */
 | 
				
			||||||
 | 
						int timerfd;
 | 
				
			||||||
 | 
						/* counter group of per-instance counters */
 | 
				
			||||||
 | 
						struct rate_ctr_group *ctrg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct rtpsim_connection **connections;
 | 
				
			||||||
 | 
						/* size of 'connections' in number of pointers */
 | 
				
			||||||
 | 
						unsigned int connections_size;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_global {
 | 
				
			||||||
 | 
						/* global list of instances */
 | 
				
			||||||
 | 
						struct llist_head instances;
 | 
				
			||||||
 | 
						pthread_rwlock_t rwlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct ctrl_handle *ctrl;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						DMAIN,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum codec_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct rtpsim_global *g_rtpsim;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_connection *rtpsim_conn_find(struct rtpsim_instance *ri, const char *cname);
 | 
				
			||||||
 | 
					struct rtpsim_connection *rtpsim_conn_reserve(struct rtpsim_instance *ri, const char *cname, enum codec_type codec);
 | 
				
			||||||
 | 
					int rtpsim_conn_start(struct rtpsim_connection *rtpc);
 | 
				
			||||||
 | 
					void rtpsim_conn_stop(struct rtpsim_connection *rtpc);
 | 
				
			||||||
 | 
					void rtpsim_conn_unreserve(struct rtpsim_connection *rtpc);
 | 
				
			||||||
 | 
					int rtpsim_conn_connect(struct rtpsim_connection *rtpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rtpsource_ctrl_cmds_install(void);
 | 
				
			||||||
							
								
								
									
										560
									
								
								contrib/rtp-load-gen/rtp-load-gen.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								contrib/rtp-load-gen/rtp-load-gen.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,560 @@
 | 
				
			|||||||
 | 
					#include <liburing.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <sys/timerfd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/sockaddr_str.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/stats.h>
 | 
				
			||||||
 | 
					#include <osmocom/netif/rtp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					#include "rtp_provider.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* use a separate rx-completion thread: submit from main, reap from completion */
 | 
				
			||||||
 | 
					//#define USE_CQ_THREAD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* use registered files: Doesn't seem to work with sockets? */
 | 
				
			||||||
 | 
					//#define USE_REGISTERED_FILES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* use registered buffers (mapped once into kernel, rather than at every write */
 | 
				
			||||||
 | 
					#define USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* number of sockets/flows to create */
 | 
				
			||||||
 | 
					#define NUM_FLOWS	4096
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* number of workers to spawn.  Each worker will get an equal share of NR_FLOWS to work on */
 | 
				
			||||||
 | 
					#define NR_WORKERS	4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* size of rx/tx buffer for one RTP frame */
 | 
				
			||||||
 | 
					#define BUF_SIZE	256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUM_FLOWS_PER_WORKER	(NUM_FLOWS/NR_WORKERS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TX_BUF_IDX	0
 | 
				
			||||||
 | 
					#define RX_BUF_IDX	1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_global *g_rtpsim;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum rtpsim_conn_ctr {
 | 
				
			||||||
 | 
						RTP_CONN_CTR_TX_PKTS,
 | 
				
			||||||
 | 
						RTP_CONN_CTR_TX_BYTES,
 | 
				
			||||||
 | 
						RTP_CONN_CTR_RX_PKTS,
 | 
				
			||||||
 | 
						RTP_CONN_CTR_RX_BYTES,
 | 
				
			||||||
 | 
						RTP_CONN_CTR_RX_INVALID,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc rtpsim_conn_ctrs[] = {
 | 
				
			||||||
 | 
						[RTP_CONN_CTR_TX_PKTS] = { "tx_pkts:total", "Transmitted packets" },
 | 
				
			||||||
 | 
						[RTP_CONN_CTR_TX_BYTES] = { "tx_bytes:total", "Transmitted bytes" },
 | 
				
			||||||
 | 
						[RTP_CONN_CTR_RX_PKTS] = { "rx_pkts:total", "Received packets (total)" },
 | 
				
			||||||
 | 
						[RTP_CONN_CTR_RX_BYTES] = { "rx_bytes:total", "Transmitted bytes" },
 | 
				
			||||||
 | 
						[RTP_CONN_CTR_RX_INVALID] = { "rx_pkts:invalid", "Received packets (invalidl)" },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const struct rate_ctr_group_desc rtpsim_conn_ctrg_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "rtpsim_conn",
 | 
				
			||||||
 | 
						.group_description = "RTP Simulator Connection",
 | 
				
			||||||
 | 
						.class_id = 0,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(rtpsim_conn_ctrs),
 | 
				
			||||||
 | 
						.ctr_desc = rtpsim_conn_ctrs,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum rtpsim_ctr {
 | 
				
			||||||
 | 
						RTP_INST_TIMERS_TOTAL,
 | 
				
			||||||
 | 
						RTP_INST_TIMERS_LATE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const struct rate_ctr_desc rtpsim_ctrs[] = {
 | 
				
			||||||
 | 
						[RTP_INST_TIMERS_TOTAL] = { "timers:total", "Timers expiring (total)" },
 | 
				
			||||||
 | 
						[RTP_INST_TIMERS_LATE] = { "timers:late", "Timers expiring (late)" },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static const struct rate_ctr_group_desc rtpsim_ctrg_desc = {
 | 
				
			||||||
 | 
						.group_name_prefix = "rtpsim",
 | 
				
			||||||
 | 
						.group_description = "RTP Simulator Instance",
 | 
				
			||||||
 | 
						.class_id = 0,
 | 
				
			||||||
 | 
						.num_ctr = ARRAY_SIZE(rtpsim_ctrs),
 | 
				
			||||||
 | 
						.ctr_desc = rtpsim_ctrs,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtpsim_instance *rtpsim_instance_init(void *ctx, const struct rtpsim_instance_cfg *rmp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_instance *ri = talloc_zero(ctx, struct rtpsim_instance);
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ri)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						ri->connections_size = NUM_FLOWS_PER_WORKER;
 | 
				
			||||||
 | 
						ri->connections = talloc_zero_size(ri, sizeof(struct rtpsim_connection *)*ri->connections_size);
 | 
				
			||||||
 | 
						if (!ri->connections) {
 | 
				
			||||||
 | 
							talloc_free(ri);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ri->cfg = *rmp;
 | 
				
			||||||
 | 
						rc = io_uring_queue_init(NUM_FLOWS_PER_WORKER*2, &ri->ring, 0);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							talloc_free(ri);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ri->ctrg = rate_ctr_group_alloc(ri, &rtpsim_ctrg_desc, rmp->num);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ri->ctrg);
 | 
				
			||||||
 | 
						return ri;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rtpsim_instance_conn_add(struct rtpsim_instance *ri, struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ri->connections_size; i++) {
 | 
				
			||||||
 | 
							if (ri->connections[i] == NULL) {
 | 
				
			||||||
 | 
								ri->connections[i] = rtpc;
 | 
				
			||||||
 | 
								rtpc->idx = i;
 | 
				
			||||||
 | 
								return i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -ENOSPC;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rtpsim_connection *
 | 
				
			||||||
 | 
					rtpsim_conn_open_bind(struct rtpsim_instance *ri, const struct rtpsim_connection_cfg *rcfg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc = talloc_zero(ri, struct rtpsim_connection);
 | 
				
			||||||
 | 
						struct osmo_sockaddr sa_local;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rtpc)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtpc->inst = ri;
 | 
				
			||||||
 | 
						rtpc->cfg = *rcfg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_sockaddr_str_to_sockaddr(&rtpc->cfg.local, &sa_local.u.sas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_sock_init_osa(SOCK_DGRAM, IPPROTO_UDP, &sa_local, NULL, OSMO_SOCK_F_BIND);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							talloc_free(rtpc);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtpc->fd = rc;
 | 
				
			||||||
 | 
						rtpc->ctrg = rate_ctr_group_alloc(rtpc, &rtpsim_conn_ctrg_desc, rtpc->cfg.local.port);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rtpc->ctrg);
 | 
				
			||||||
 | 
					#ifndef USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
						rtpc->tx.buf = talloc_zero_size(rtpc, BUF_SIZE);
 | 
				
			||||||
 | 
						rtpc->rx.buf = talloc_zero_size(rtpc, BUF_SIZE);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						OSMO_ASSERT(rtpsim_instance_conn_add(ri, rtpc) >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rtpc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* find a connection for given cname (may be NULL to find unused connection) */
 | 
				
			||||||
 | 
					struct rtpsim_connection *rtpsim_conn_find(struct rtpsim_instance *ri, const char *cname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ri->connections_size; i++) {
 | 
				
			||||||
 | 
							struct rtpsim_connection *rtpc = ri->connections[i];
 | 
				
			||||||
 | 
							if (!rtpc)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (!rtpc->cname) {
 | 
				
			||||||
 | 
								if (!cname)
 | 
				
			||||||
 | 
									return rtpc;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!strcmp(rtpc->cname, cname))
 | 
				
			||||||
 | 
								return rtpc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* reserve a connection; associates cname with it */
 | 
				
			||||||
 | 
					struct rtpsim_connection *rtpsim_conn_reserve(struct rtpsim_instance *ri, const char *cname,
 | 
				
			||||||
 | 
										      enum codec_type codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc;
 | 
				
			||||||
 | 
						const struct rtp_provider *rtp_prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtp_prov = rtp_provider_find("static"); // TODO: configurable */
 | 
				
			||||||
 | 
						OSMO_ASSERT(rtp_prov);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtpc = rtpsim_conn_find(ri, NULL);
 | 
				
			||||||
 | 
						if (!rtpc)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* this is called from main thread, we cannot use per-thread talloc contexts
 | 
				
			||||||
 | 
						 * such as ri or rtpc */
 | 
				
			||||||
 | 
						rtpc->cname = talloc_strdup(g_rtpsim, cname);
 | 
				
			||||||
 | 
						rtpc->tx.rtp_prov_inst = rtp_provider_instance_alloc(g_rtpsim, rtp_prov, codec);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rtpc->tx.rtp_prov_inst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* re-start from zero transmit sequence number */
 | 
				
			||||||
 | 
						rtpc->tx.seq = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rtpc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rtpsim_conn_start(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtpc->tx.enabled = true;
 | 
				
			||||||
 | 
						rtpc->rx.enabled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtpsim_conn_stop(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* disable Rx and Tx */
 | 
				
			||||||
 | 
						rtpc->tx.enabled = false;
 | 
				
			||||||
 | 
						rtpc->rx.enabled = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* unreserve a connection; stops all rx/tx and removes cname */
 | 
				
			||||||
 | 
					void rtpsim_conn_unreserve(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtp_provider_instance_free(rtpc->tx.rtp_prov_inst);
 | 
				
			||||||
 | 
						rtpc->tx.rtp_prov_inst = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(rtpc->cname);
 | 
				
			||||||
 | 
						rtpc->cname = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* connect a RTP connection to its remote peer (as in rtpc->cfg.remote) */
 | 
				
			||||||
 | 
					int rtpsim_conn_connect(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_sockaddr sa_remote;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_sockaddr_str_to_sockaddr(&rtpc->cfg.remote, &sa_remote.u.sas);
 | 
				
			||||||
 | 
						rc = connect(rtpc->fd, &sa_remote.u.sa, sizeof(struct osmo_sockaddr));
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* transmit one RTP frame for given connection */
 | 
				
			||||||
 | 
					static int rtpsim_conn_tx_frame(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtp_hdr *rtph = (struct rtp_hdr *) rtpc->tx.buf;
 | 
				
			||||||
 | 
						struct io_uring_sqe *sqe;
 | 
				
			||||||
 | 
						uint8_t *payload;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rtph->version = RTP_VERSION;
 | 
				
			||||||
 | 
						rtph->padding = 0;
 | 
				
			||||||
 | 
						rtph->extension = 0;
 | 
				
			||||||
 | 
						rtph->csrc_count = 0;
 | 
				
			||||||
 | 
						rtph->marker = 0;
 | 
				
			||||||
 | 
						rtph->payload_type = rtpc->cfg.pt;
 | 
				
			||||||
 | 
						rtph->sequence = htons(rtpc->tx.seq++);
 | 
				
			||||||
 | 
						rtph->timestamp = htonl(rtpc->tx.timestamp);
 | 
				
			||||||
 | 
						rtpc->tx.timestamp += rtpc->cfg.duration;
 | 
				
			||||||
 | 
						rtph->ssrc = htonl(rtpc->cfg.ssrc);
 | 
				
			||||||
 | 
						payload = rtpc->tx.buf + sizeof(*rtph);
 | 
				
			||||||
 | 
						/* add payload data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rtp_provider_instance_gen_frame(rtpc->tx.rtp_prov_inst, payload, BUF_SIZE-sizeof(*rtph));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
						rtpc->tx.buf_len = sizeof(*rtph) + rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sqe = io_uring_get_sqe(&rtpc->inst->ring);
 | 
				
			||||||
 | 
						OSMO_ASSERT(sqe);
 | 
				
			||||||
 | 
						sqe->user_data = rtpc->idx;
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_FILES
 | 
				
			||||||
 | 
						io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
						io_uring_prep_write_fixed(sqe, rtpc->idx, rtpc->tx.buf, rtpc->tx.buf_len, 0, TX_BUF_IDX);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						io_uring_prep_write(sqe, rtpc->idx, rtpc->tx.buf, rtpc->tx.buf_len, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#else /* REGISTERED FILES */
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
						io_uring_prep_write_fixed(sqe, rtpc->fd, rtpc->tx.buf, rtpc->tx.buf_len, 0, TX_BUF_IDX);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						io_uring_prep_write(sqe, rtpc->fd, rtpc->tx.buf, rtpc->tx.buf_len, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif /* REGISTERED_FILES */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* submit RX buffer for a RTP frame on given connection */
 | 
				
			||||||
 | 
					static int rtpsim_conn_rx_prep(struct rtpsim_connection *rtpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct io_uring_sqe *sqe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sqe = io_uring_get_sqe(&rtpc->inst->ring);
 | 
				
			||||||
 | 
						OSMO_ASSERT(sqe);
 | 
				
			||||||
 | 
						sqe->user_data = 0x8000000 | rtpc->idx;
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_FILES
 | 
				
			||||||
 | 
						io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
 | 
				
			||||||
 | 
						/* FIXME */
 | 
				
			||||||
 | 
					#else /* REGISTERED FILES */
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
						io_uring_prep_read_fixed(sqe, rtpc->fd, rtpc->rx.buf, BUF_SIZE, 0, RX_BUF_IDX);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						io_uring_prep_read(sqe, rtpc->fd, rtpc->rx.buf, BUF_SIZE, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif /* REGISTERED_FILES */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* process one completion entry */
 | 
				
			||||||
 | 
					static void handle_completion(struct rtpsim_instance *ri, struct io_uring_cqe *cqe)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc = ri->connections[cqe->user_data & 0x7fffffff];
 | 
				
			||||||
 | 
						OSMO_ASSERT(rtpc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cqe->user_data & 0x80000000) {
 | 
				
			||||||
 | 
							/* read */
 | 
				
			||||||
 | 
							rate_ctr_inc(&rtpc->ctrg->ctr[RTP_CONN_CTR_RX_PKTS]);
 | 
				
			||||||
 | 
							rate_ctr_add(&rtpc->ctrg->ctr[RTP_CONN_CTR_RX_BYTES], cqe->res);
 | 
				
			||||||
 | 
							OSMO_ASSERT(cqe->res >= 0);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* write */
 | 
				
			||||||
 | 
							rate_ctr_inc(&rtpc->ctrg->ctr[RTP_CONN_CTR_TX_PKTS]);
 | 
				
			||||||
 | 
							rate_ctr_add(&rtpc->ctrg->ctr[RTP_CONN_CTR_TX_BYTES], cqe->res);
 | 
				
			||||||
 | 
							OSMO_ASSERT(cqe->res == sizeof(struct rtp_hdr) + 33);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						io_uring_cqe_seen(&ri->ring, cqe);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_CQ_THREAD
 | 
				
			||||||
 | 
					/* 'main' function for separate completion queue reaping thread */
 | 
				
			||||||
 | 
					static void *reap_completion(void *_ri)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_instance *ri = _ri;
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							struct io_uring_cqe *cqe;
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = io_uring_wait_cqe(&ri->ring, &cqe);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
							handle_completion(ri, cqe);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int osmo_ctx_init(const char *id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rtpsim_main(const struct rtpsim_instance_cfg *rmp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtpsim_instance *ri;
 | 
				
			||||||
 | 
						struct rtpsim_connection *rtpc;
 | 
				
			||||||
 | 
						int i, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char namebuf[32];
 | 
				
			||||||
 | 
						snprintf(namebuf, sizeof(namebuf), "rtpsim_worker%d", rmp->num);
 | 
				
			||||||
 | 
						osmo_ctx_init(namebuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ri = rtpsim_instance_init(OTC_GLOBAL, rmp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pthread_rwlock_wrlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
						llist_add_tail(&ri->list, &g_rtpsim->instances);
 | 
				
			||||||
 | 
						pthread_rwlock_unlock(&g_rtpsim->rwlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create desired number of sockets */
 | 
				
			||||||
 | 
						printf("binding sockets\n");
 | 
				
			||||||
 | 
						for (i = 0; i < rmp->num_flows; i++) {
 | 
				
			||||||
 | 
							struct rtpsim_connection *rtpc;
 | 
				
			||||||
 | 
							struct rtpsim_connection_cfg rcfg = {};
 | 
				
			||||||
 | 
							rcfg.local = (struct osmo_sockaddr_str) {
 | 
				
			||||||
 | 
								.af = AF_INET,
 | 
				
			||||||
 | 
								.ip = "127.0.0.1",
 | 
				
			||||||
 | 
								.port = rmp->base_port + 2*i,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							rcfg.remote = (struct osmo_sockaddr_str) {
 | 
				
			||||||
 | 
								.af = AF_INET,
 | 
				
			||||||
 | 
								.ip = "127.0.0.1",
 | 
				
			||||||
 | 
								.port = rmp->base_port + 2*i,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							rcfg.pt = 3;
 | 
				
			||||||
 | 
							rcfg.ssrc = 0x80000000 + rmp->base_port + i;
 | 
				
			||||||
 | 
							rcfg.duration = 160;	/* 8000 Hz sampling rate / 50 Hz RTP rate */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rtpc = rtpsim_conn_open_bind(ri, &rcfg);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtpc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 1
 | 
				
			||||||
 | 
						/* HACK */
 | 
				
			||||||
 | 
						printf("connecting sockets\n");
 | 
				
			||||||
 | 
						for (i = 0; i < rmp->num_flows; i++) {
 | 
				
			||||||
 | 
							char namebuf[32];
 | 
				
			||||||
 | 
							snprintf(namebuf, sizeof(namebuf), "conn%d", i);
 | 
				
			||||||
 | 
							struct rtpsim_connection *rtpc = rtpsim_conn_reserve(ri, namebuf, CODEC_GSM_FR);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtpc);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtpsim_conn_connect(rtpc) == 0);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rtpsim_conn_start(rtpc) == 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_FILES
 | 
				
			||||||
 | 
						/* register all our file descriptors; seems to fail on 5.8.x ? */
 | 
				
			||||||
 | 
						int fds[NUM_FLOWS_PER_WORKER];
 | 
				
			||||||
 | 
						for (i = 0; i < ri->connections_size; i++) {
 | 
				
			||||||
 | 
							if (!rtpc) {
 | 
				
			||||||
 | 
								fds[i] = -1;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rtpc = ri->connections[i];
 | 
				
			||||||
 | 
							fds[i] = rtpc->fd;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("Registering %d files\n", i);
 | 
				
			||||||
 | 
						rc = io_uring_register_files(&ri->ring, fds, i);
 | 
				
			||||||
 | 
						printf("rc = %d: %s\n", rc, strerror(-rc));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_REGISTERED_BUFFERS
 | 
				
			||||||
 | 
						/* register two large buffers for Rx and Tx; assign per-connection
 | 
				
			||||||
 | 
						 * buffers within those two registered buffers */
 | 
				
			||||||
 | 
						void *largebuf_tx = talloc_zero_size(ri, rmp->num_flows * BUF_SIZE);
 | 
				
			||||||
 | 
						void *largebuf_rx = talloc_zero_size(ri, rmp->num_flows * BUF_SIZE);
 | 
				
			||||||
 | 
						struct iovec iov[2] = {
 | 
				
			||||||
 | 
							[TX_BUF_IDX] = {
 | 
				
			||||||
 | 
								.iov_base = largebuf_tx,
 | 
				
			||||||
 | 
								.iov_len = rmp->num_flows * BUF_SIZE,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							[RX_BUF_IDX] = {
 | 
				
			||||||
 | 
								.iov_base = largebuf_rx,
 | 
				
			||||||
 | 
								.iov_len = rmp->num_flows * BUF_SIZE,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						printf("Registering buffers for %d sockets\n", i);
 | 
				
			||||||
 | 
						rc = io_uring_register_buffers(&ri->ring, iov, ARRAY_SIZE(iov));
 | 
				
			||||||
 | 
						printf("rc = %d: %s\n", rc, strerror(-rc));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						for (i = 0; i < ri->connections_size; i++) {
 | 
				
			||||||
 | 
							rtpc = ri->connections[i];
 | 
				
			||||||
 | 
							if (!rtpc)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							rtpc->tx.buf = largebuf_tx + (i * BUF_SIZE);
 | 
				
			||||||
 | 
							rtpc->rx.buf = largebuf_rx + (i * BUF_SIZE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_CQ_THREAD
 | 
				
			||||||
 | 
						/* start a separate completion thread instead of handling completions in-line */
 | 
				
			||||||
 | 
						pthread_t complete;
 | 
				
			||||||
 | 
						rc = pthread_create(&complete, NULL, reap_completion, ri);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* start timerfd every 20ms */
 | 
				
			||||||
 | 
						ri->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ri->timerfd >= 0);
 | 
				
			||||||
 | 
						struct itimerspec its = (struct itimerspec) {
 | 
				
			||||||
 | 
							.it_interval = { 0, 20*1000*1000 },
 | 
				
			||||||
 | 
							.it_value = { 0, 20*1000*1000 },
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						rc = timerfd_settime(ri->timerfd, 0, &its, NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* start transmitting */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							/* the assumption here is that every flow wants to write 50
 | 
				
			||||||
 | 
							 * packets per second, so we try try to submit one write for each
 | 
				
			||||||
 | 
							 * flow every 20ms */
 | 
				
			||||||
 | 
							unsigned int submit_granularity = rmp->num_flows/50;
 | 
				
			||||||
 | 
							/* number of 20ms timer expirations */
 | 
				
			||||||
 | 
							uint64_t num_exp;
 | 
				
			||||||
 | 
							unsigned int t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (submit_granularity <= 0)
 | 
				
			||||||
 | 
								submit_granularity = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* read from timerfd to pace the 20ms inter packet interval */
 | 
				
			||||||
 | 
							rc = read(ri->timerfd, &num_exp, sizeof(num_exp));
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc == sizeof(num_exp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rate_ctr_add(&ri->ctrg->ctr[RTP_INST_TIMERS_TOTAL], num_exp);
 | 
				
			||||||
 | 
							if (num_exp != 1) {
 | 
				
			||||||
 | 
								fputc('X', stdout);
 | 
				
			||||||
 | 
								rate_ctr_add(&ri->ctrg->ctr[RTP_INST_TIMERS_LATE], num_exp-1);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								fputc('.', stdout);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fflush(stdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (t = 0; t < num_exp; t++) {
 | 
				
			||||||
 | 
								for (i = 0; i < ri->connections_size; i++) {
 | 
				
			||||||
 | 
									rtpc = ri->connections[i];
 | 
				
			||||||
 | 
									if (!rtpc)
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									if (rtpc->tx.enabled)
 | 
				
			||||||
 | 
										rtpsim_conn_tx_frame(rtpc);
 | 
				
			||||||
 | 
									if (rtpc->rx.enabled)
 | 
				
			||||||
 | 
										rtpsim_conn_rx_prep(rtpc);
 | 
				
			||||||
 | 
									if ((i % submit_granularity) == 0) {
 | 
				
			||||||
 | 
										int pending = io_uring_submit(&ri->ring);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef USE_CQ_THREAD
 | 
				
			||||||
 | 
										for (int j = 0; j < pending; j++) {
 | 
				
			||||||
 | 
											struct io_uring_cqe *cqe;
 | 
				
			||||||
 | 
											int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											rc = io_uring_wait_cqe(&ri->ring, &cqe);
 | 
				
			||||||
 | 
											OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
											handle_completion(ri, cqe);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					#endif /* USE_CQ_THREAD */
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *rtpsim_worker_thread(void *_rmp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtpsim_main((struct rtpsim_instance_cfg *)_rmp);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pthread_t worker[NR_WORKERS];
 | 
				
			||||||
 | 
						struct rtpsim_instance_cfg rmp[NR_WORKERS];
 | 
				
			||||||
 | 
						int i, rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g_rtpsim = talloc_zero(NULL, struct rtpsim_global);
 | 
				
			||||||
 | 
						OSMO_ASSERT(g_rtpsim);
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&g_rtpsim->instances);
 | 
				
			||||||
 | 
						pthread_rwlock_init(&g_rtpsim->rwlock, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_init_logging2(g_rtpsim, NULL);
 | 
				
			||||||
 | 
					//	osmo_stats_init(g_rtpsim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create worker threads */
 | 
				
			||||||
 | 
						for (i = 0; i < NR_WORKERS; i++) {
 | 
				
			||||||
 | 
							int rc;
 | 
				
			||||||
 | 
							rmp[i].num = i;
 | 
				
			||||||
 | 
							rmp[i].num_flows = NUM_FLOWS_PER_WORKER;
 | 
				
			||||||
 | 
							rmp[i].base_port = 10000 + i * (2 * rmp[i].num_flows);
 | 
				
			||||||
 | 
							rc = pthread_create(&worker[i], NULL, rtpsim_worker_thread, &rmp[i]);
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* CTRL interface */
 | 
				
			||||||
 | 
						//g_rtpsim->ctrl = ctrl_interface_setup_dynip(g_rss, ctrl_vty_get_bind_addr(), 11111, NULL);
 | 
				
			||||||
 | 
						g_rtpsim->ctrl = ctrl_interface_setup_dynip(g_rtpsim, "127.0.0.1", 11111, NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(g_rtpsim->ctrl);
 | 
				
			||||||
 | 
						rc = rtpsource_ctrl_cmds_install();
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							osmo_select_main(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < NR_WORKERS; i++) {
 | 
				
			||||||
 | 
							pthread_join(worker[i], NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								contrib/rtp-load-gen/rtp_provider.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								contrib/rtp-load-gen/rtp_provider.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "rtp_provider.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static LLIST_HEAD(g_providers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct value_string codec_type_names[] = {
 | 
				
			||||||
 | 
						{ CODEC_ULAW,		"ULAW" },
 | 
				
			||||||
 | 
						{ CODEC_ALAW,		"ALAW" },
 | 
				
			||||||
 | 
						{ CODEC_GSM_FR,		"GSM_FR" },
 | 
				
			||||||
 | 
						{ CODEC_GSM_EFR,	"GSM_EFR" },
 | 
				
			||||||
 | 
						{ CODEC_GSM_HR,		"GSM_HR" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_4_75,	"AMR_4_75" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_5_15,	"AMR_5_15" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_5_90,	"AMR_5_90" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_6_70,	"AMR_6_70" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_7_40,	"AMR_7_40" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_7_95,	"AMR_7_95" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_10_2,	"AMR_10_2" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_12_2,	"AMR_12_2" },
 | 
				
			||||||
 | 
						{ CODEC_AMR_SID,	"AMR_SID" },
 | 
				
			||||||
 | 
						{ 0, NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtp_provider_register(struct rtp_provider *prov)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_add_tail(&prov->list, &g_providers);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct rtp_provider *rtp_provider_find(const char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtp_provider *p;
 | 
				
			||||||
 | 
						llist_for_each_entry(p, &g_providers, list) {
 | 
				
			||||||
 | 
							if (!strcmp(name, p->name))
 | 
				
			||||||
 | 
								return p;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						LOGP(DMAIN, LOGL_ERROR, "Couldn't find RTP provider '%s'\n", name);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider_instance *
 | 
				
			||||||
 | 
					rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rtp_provider_instance *pi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pi = talloc_zero(ctx, struct rtp_provider_instance);
 | 
				
			||||||
 | 
						if (!pi)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pi->provider = provider;
 | 
				
			||||||
 | 
						pi->codec = codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pi;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtp_provider_instance_free(struct rtp_provider_instance *pi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						llist_del(&pi->list);
 | 
				
			||||||
 | 
						talloc_free(pi);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						OSMO_ASSERT(pi->provider);
 | 
				
			||||||
 | 
						return pi->provider->rtp_gen(pi, out, out_size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								contrib/rtp-load-gen/rtp_provider.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								contrib/rtp-load-gen/rtp_provider.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum codec_type {
 | 
				
			||||||
 | 
						CODEC_ULAW,
 | 
				
			||||||
 | 
						CODEC_ALAW,
 | 
				
			||||||
 | 
						CODEC_GSM_FR,
 | 
				
			||||||
 | 
						CODEC_GSM_EFR,
 | 
				
			||||||
 | 
						CODEC_GSM_HR,
 | 
				
			||||||
 | 
						CODEC_AMR_4_75,
 | 
				
			||||||
 | 
						CODEC_AMR_5_15,
 | 
				
			||||||
 | 
						CODEC_AMR_5_90,
 | 
				
			||||||
 | 
						CODEC_AMR_6_70,
 | 
				
			||||||
 | 
						CODEC_AMR_7_40,
 | 
				
			||||||
 | 
						CODEC_AMR_7_95,
 | 
				
			||||||
 | 
						CODEC_AMR_10_2,
 | 
				
			||||||
 | 
						CODEC_AMR_12_2,
 | 
				
			||||||
 | 
						CODEC_AMR_SID,
 | 
				
			||||||
 | 
						_NUM_CODECS
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct value_string codec_type_names[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider_instance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider {
 | 
				
			||||||
 | 
						/* global list of RTP providers */
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create/initialie a RTP provider with specified argument string */
 | 
				
			||||||
 | 
						int (*setup)(struct rtp_provider_instance *inst, const char *arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* generate the next RTP packet; return length in octests or negative on error */
 | 
				
			||||||
 | 
						int (*rtp_gen)(struct rtp_provider_instance *inst, uint8_t *out, size_t out_size);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider_instance {
 | 
				
			||||||
 | 
						/* entry in global list of RTP provider instances */
 | 
				
			||||||
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
						/* pointer to provider of which we are an instance */
 | 
				
			||||||
 | 
						const struct rtp_provider *provider;
 | 
				
			||||||
 | 
						/* codec payload we are to generate */
 | 
				
			||||||
 | 
						enum codec_type codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* private user data */
 | 
				
			||||||
 | 
						void *priv;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void rtp_provider_register(struct rtp_provider *prov);
 | 
				
			||||||
 | 
					const struct rtp_provider *rtp_provider_find(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtp_provider_instance *rtp_provider_instance_alloc(void *ctx, const struct rtp_provider *provider, enum codec_type codec);
 | 
				
			||||||
 | 
					void rtp_provider_instance_free(struct rtp_provider_instance *pi);
 | 
				
			||||||
 | 
					int rtp_provider_instance_gen_frame(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size);
 | 
				
			||||||
							
								
								
									
										108
									
								
								contrib/rtp-load-gen/rtp_provider_static.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								contrib/rtp-load-gen/rtp_provider_static.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <osmocom/codec/codec.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "rtp_provider.h"
 | 
				
			||||||
 | 
					#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rtp_provider static_provider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t len4codec[_NUM_CODECS] = {
 | 
				
			||||||
 | 
					    [CODEC_ULAW] = 160,
 | 
				
			||||||
 | 
					    [CODEC_ALAW] = 160,
 | 
				
			||||||
 | 
					    [CODEC_GSM_FR] = GSM_FR_BYTES,
 | 
				
			||||||
 | 
					    [CODEC_GSM_EFR] = GSM_EFR_BYTES,
 | 
				
			||||||
 | 
					    [CODEC_GSM_HR] = GSM_HR_BYTES,
 | 
				
			||||||
 | 
					    [CODEC_AMR_4_75] = 12,
 | 
				
			||||||
 | 
					    [CODEC_AMR_5_15] = 13,
 | 
				
			||||||
 | 
					    [CODEC_AMR_5_90] = 15,
 | 
				
			||||||
 | 
					    [CODEC_AMR_6_70] = 17,
 | 
				
			||||||
 | 
					    [CODEC_AMR_7_40] = 19,
 | 
				
			||||||
 | 
					    [CODEC_AMR_7_95] = 20,
 | 
				
			||||||
 | 
					    [CODEC_AMR_10_2] = 26,
 | 
				
			||||||
 | 
					    [CODEC_AMR_12_2] = 31,
 | 
				
			||||||
 | 
					    [CODEC_AMR_SID] = 5,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* generate a static / fixed RTP payload of matching codec/mode */
 | 
				
			||||||
 | 
					static int rtp_gen_static(struct rtp_provider_instance *pi, uint8_t *out, size_t out_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(pi->provider == &static_provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = len4codec[pi->codec];
 | 
				
			||||||
 | 
						if (out_size < len) {
 | 
				
			||||||
 | 
							LOGP(DMAIN, LOGL_ERROR, "out_size %zu < %u\n", out_size, len);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(out, 0, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (pi->codec) {
 | 
				
			||||||
 | 
						case CODEC_ULAW:
 | 
				
			||||||
 | 
						case CODEC_ALAW:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_GSM_FR:
 | 
				
			||||||
 | 
							out[0] = (out[0] & 0x0f) | 0xD0; /* mask in first four bit for FR */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_GSM_EFR:
 | 
				
			||||||
 | 
							out[0] = (out[0] & 0x0f) | 0xC0; /* mask in first four bit for EFR */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_GSM_HR:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_4_75:
 | 
				
			||||||
 | 
							out[0] = 0 << 4;
 | 
				
			||||||
 | 
							out[1] = 0 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_5_15:
 | 
				
			||||||
 | 
							out[0] = 1 << 4;
 | 
				
			||||||
 | 
							out[1] = 1 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_5_90:
 | 
				
			||||||
 | 
							out[0] = 2 << 4;
 | 
				
			||||||
 | 
							out[1] = 2 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_6_70:
 | 
				
			||||||
 | 
							out[0] = 3 << 4;
 | 
				
			||||||
 | 
							out[1] = 3 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_7_40:
 | 
				
			||||||
 | 
							out[0] = 4 << 4;
 | 
				
			||||||
 | 
							out[1] = 4 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_7_95:
 | 
				
			||||||
 | 
							out[0] = 5 << 4;
 | 
				
			||||||
 | 
							out[1] = 5 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_10_2:
 | 
				
			||||||
 | 
							out[0] = 6 << 4;
 | 
				
			||||||
 | 
							out[1] = 6 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_12_2:
 | 
				
			||||||
 | 
							out[0] = 7 << 4;
 | 
				
			||||||
 | 
							out[1] = 7 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case CODEC_AMR_SID:
 | 
				
			||||||
 | 
							out[0] = 2 << 4; /* CMR: 5.90 */
 | 
				
			||||||
 | 
							out[0] = 8 << 3;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							OSMO_ASSERT(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct rtp_provider static_provider = {
 | 
				
			||||||
 | 
						.name = "static",
 | 
				
			||||||
 | 
						.rtp_gen = &rtp_gen_static,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __attribute__((constructor)) rtp_provider_static_constr(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtp_provider_register(&static_provider);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								contrib/simcom2rtp/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								contrib/simcom2rtp/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					CFLAGS:= -O2 -g -Wall $(shell pkg-config --cflags libosmocore libosmotrau)
 | 
				
			||||||
 | 
					LIBS:= $(shell pkg-config --libs libosmocore libosmotrau)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: osmo-simcom2rtp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					osmo-simcom2rtp: g711.o g711_table.o simcom2rtp.o
 | 
				
			||||||
 | 
						$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%.o: %.c
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) -o $@ -c $^
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										313
									
								
								contrib/simcom2rtp/g711.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								contrib/simcom2rtp/g711.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This source code is a product of Sun Microsystems, Inc. and is provided
 | 
				
			||||||
 | 
					 * for unrestricted use.  Users may copy or modify this source code without
 | 
				
			||||||
 | 
					 * charge.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
 | 
				
			||||||
 | 
					 * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 | 
				
			||||||
 | 
					 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sun source code is provided with no support and without any obligation on
 | 
				
			||||||
 | 
					 * the part of Sun Microsystems, Inc. to assist in its use, correction,
 | 
				
			||||||
 | 
					 * modification or enhancement.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 | 
				
			||||||
 | 
					 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
 | 
				
			||||||
 | 
					 * OR ANY PART THEREOF.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 | 
				
			||||||
 | 
					 * or profits or other special, indirect and consequential damages, even if
 | 
				
			||||||
 | 
					 * Sun has been advised of the possibility of such damages.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sun Microsystems, Inc.
 | 
				
			||||||
 | 
					 * 2550 Garcia Avenue
 | 
				
			||||||
 | 
					 * Mountain View, California  94043
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * December 30, 1994:
 | 
				
			||||||
 | 
					 * Functions linear2alaw, linear2ulaw have been updated to correctly
 | 
				
			||||||
 | 
					 * convert unquantized 16 bit values.
 | 
				
			||||||
 | 
					 * Tables for direct u- to A-law and A- to u-law conversions have been
 | 
				
			||||||
 | 
					 * corrected.
 | 
				
			||||||
 | 
					 * Borge Lindberg, Center for PersonKommunikation, Aalborg University.
 | 
				
			||||||
 | 
					 * bli@cpk.auc.dk
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Downloaded from comp.speech site in Cambridge.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * g711.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * u-law, A-law and linear PCM conversions.
 | 
				
			||||||
 | 
					 * Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.c
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
 | 
				
			||||||
 | 
					#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
 | 
				
			||||||
 | 
					#define	NSEGS		(8)		/* Number of A-law segments. */
 | 
				
			||||||
 | 
					#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
 | 
				
			||||||
 | 
					#define	SEG_MASK	(0x70)		/* Segment field mask. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static short seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
 | 
				
			||||||
 | 
								    0x1FF, 0x3FF, 0x7FF, 0xFFF};
 | 
				
			||||||
 | 
					static short seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
 | 
				
			||||||
 | 
								    0x3FF, 0x7FF, 0xFFF, 0x1FFF};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* copy from CCITT G.711 specifications */
 | 
				
			||||||
 | 
					unsigned char _u2a[128] = {			/* u- to A-law conversions */
 | 
				
			||||||
 | 
						1,	1,	2,	2,	3,	3,	4,	4,
 | 
				
			||||||
 | 
						5,	5,	6,	6,	7,	7,	8,	8,
 | 
				
			||||||
 | 
						9,	10,	11,	12,	13,	14,	15,	16,
 | 
				
			||||||
 | 
						17,	18,	19,	20,	21,	22,	23,	24,
 | 
				
			||||||
 | 
						25,	27,	29,	31,	33,	34,	35,	36,
 | 
				
			||||||
 | 
						37,	38,	39,	40,	41,	42,	43,	44,
 | 
				
			||||||
 | 
						46,	48,	49,	50,	51,	52,	53,	54,
 | 
				
			||||||
 | 
						55,	56,	57,	58,	59,	60,	61,	62,
 | 
				
			||||||
 | 
						64,	65,	66,	67,	68,	69,	70,	71,
 | 
				
			||||||
 | 
						72,	73,	74,	75,	76,	77,	78,	79,
 | 
				
			||||||
 | 
					/* corrected:
 | 
				
			||||||
 | 
						81,	82,	83,	84,	85,	86,	87,	88, 
 | 
				
			||||||
 | 
					   should be: */
 | 
				
			||||||
 | 
						80,	82,	83,	84,	85,	86,	87,	88,
 | 
				
			||||||
 | 
						89,	90,	91,	92,	93,	94,	95,	96,
 | 
				
			||||||
 | 
						97,	98,	99,	100,	101,	102,	103,	104,
 | 
				
			||||||
 | 
						105,	106,	107,	108,	109,	110,	111,	112,
 | 
				
			||||||
 | 
						113,	114,	115,	116,	117,	118,	119,	120,
 | 
				
			||||||
 | 
						121,	122,	123,	124,	125,	126,	127,	128};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned char _a2u[128] = {			/* A- to u-law conversions */
 | 
				
			||||||
 | 
						1,	3,	5,	7,	9,	11,	13,	15,
 | 
				
			||||||
 | 
						16,	17,	18,	19,	20,	21,	22,	23,
 | 
				
			||||||
 | 
						24,	25,	26,	27,	28,	29,	30,	31,
 | 
				
			||||||
 | 
						32,	32,	33,	33,	34,	34,	35,	35,
 | 
				
			||||||
 | 
						36,	37,	38,	39,	40,	41,	42,	43,
 | 
				
			||||||
 | 
						44,	45,	46,	47,	48,	48,	49,	49,
 | 
				
			||||||
 | 
						50,	51,	52,	53,	54,	55,	56,	57,
 | 
				
			||||||
 | 
						58,	59,	60,	61,	62,	63,	64,	64,
 | 
				
			||||||
 | 
						65,	66,	67,	68,	69,	70,	71,	72,
 | 
				
			||||||
 | 
					/* corrected:
 | 
				
			||||||
 | 
						73,	74,	75,	76,	77,	78,	79,	79,
 | 
				
			||||||
 | 
					   should be: */
 | 
				
			||||||
 | 
						73,	74,	75,	76,	77,	78,	79,	80,
 | 
				
			||||||
 | 
						80,	81,	82,	83,	84,	85,	86,	87,
 | 
				
			||||||
 | 
						88,	89,	90,	91,	92,	93,	94,	95,
 | 
				
			||||||
 | 
						96,	97,	98,	99,	100,	101,	102,	103,
 | 
				
			||||||
 | 
						104,	105,	106,	107,	108,	109,	110,	111,
 | 
				
			||||||
 | 
						112,	113,	114,	115,	116,	117,	118,	119,
 | 
				
			||||||
 | 
						120,	121,	122,	123,	124,	125,	126,	127};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static short search(
 | 
				
			||||||
 | 
					   short val,
 | 
				
			||||||
 | 
					   short *table,
 | 
				
			||||||
 | 
					   short size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short i;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   for (i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					      if (val <= *table++)
 | 
				
			||||||
 | 
						 return (i);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return (size);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *		Linear Input Code	Compressed Code
 | 
				
			||||||
 | 
					 *	------------------------	---------------
 | 
				
			||||||
 | 
					 *	0000000wxyza			000wxyz
 | 
				
			||||||
 | 
					 *	0000001wxyza			001wxyz
 | 
				
			||||||
 | 
					 *	000001wxyzab			010wxyz
 | 
				
			||||||
 | 
					 *	00001wxyzabc			011wxyz
 | 
				
			||||||
 | 
					 *	0001wxyzabcd			100wxyz
 | 
				
			||||||
 | 
					 *	001wxyzabcde			101wxyz
 | 
				
			||||||
 | 
					 *	01wxyzabcdef			110wxyz
 | 
				
			||||||
 | 
					 *	1wxyzabcdefg			111wxyz
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For further information see John C. Bellamy's Digital Telephony, 1982,
 | 
				
			||||||
 | 
					 * John Wiley & Sons, pps 98-111 and 472-476.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					linear2alaw(short pcm_val)	/* 2's complement (16-bit range) */
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short	 mask;
 | 
				
			||||||
 | 
					   short	 seg;
 | 
				
			||||||
 | 
					   unsigned char aval;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   pcm_val = pcm_val >> 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if (pcm_val >= 0) {
 | 
				
			||||||
 | 
					      mask = 0xD5;		/* sign (7th) bit = 1 */
 | 
				
			||||||
 | 
					   } else {
 | 
				
			||||||
 | 
					      mask = 0x55;		/* sign bit = 0 */
 | 
				
			||||||
 | 
					      pcm_val = -pcm_val - 1;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Convert the scaled magnitude to segment number. */
 | 
				
			||||||
 | 
					   seg = search(pcm_val, seg_aend, 8);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Combine the sign, segment, and quantization bits. */
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   if (seg >= 8)		/* out of range, return maximum value. */
 | 
				
			||||||
 | 
					      return (unsigned char) (0x7F ^ mask);
 | 
				
			||||||
 | 
					   else {
 | 
				
			||||||
 | 
					      aval = (unsigned char) seg << SEG_SHIFT;
 | 
				
			||||||
 | 
					      if (seg < 2)
 | 
				
			||||||
 | 
						 aval |= (pcm_val >> 1) & QUANT_MASK;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
						 aval |= (pcm_val >> seg) & QUANT_MASK;
 | 
				
			||||||
 | 
					      return (aval ^ mask);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * alaw2linear() - Convert an A-law value to 16-bit linear PCM
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					short
 | 
				
			||||||
 | 
					alaw2linear(
 | 
				
			||||||
 | 
					   unsigned char	a_val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short t;
 | 
				
			||||||
 | 
					   short seg;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   a_val ^= 0x55;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   t = (a_val & QUANT_MASK) << 4;
 | 
				
			||||||
 | 
					   seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
 | 
				
			||||||
 | 
					   switch (seg) {
 | 
				
			||||||
 | 
					   case 0:
 | 
				
			||||||
 | 
					      t += 8;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					   case 1:
 | 
				
			||||||
 | 
					      t += 0x108;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					   default:
 | 
				
			||||||
 | 
					      t += 0x108;
 | 
				
			||||||
 | 
					      t <<= seg - 1;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return ((a_val & SIGN_BIT) ? t : -t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	BIAS		(0x84)		/* Bias for linear code. */
 | 
				
			||||||
 | 
					#define CLIP            8159
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* linear2ulaw() - Convert a linear PCM value to u-law
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* In order to simplify the encoding process, the original linear magnitude
 | 
				
			||||||
 | 
					* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
 | 
				
			||||||
 | 
					* (33 - 8191). The result can be seen in the following encoding table:
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*	Biased Linear Input Code	Compressed Code
 | 
				
			||||||
 | 
					*	------------------------	---------------
 | 
				
			||||||
 | 
					*	00000001wxyza			000wxyz
 | 
				
			||||||
 | 
					*	0000001wxyzab			001wxyz
 | 
				
			||||||
 | 
					*	000001wxyzabc			010wxyz
 | 
				
			||||||
 | 
					*	00001wxyzabcd			011wxyz
 | 
				
			||||||
 | 
					*	0001wxyzabcde			100wxyz
 | 
				
			||||||
 | 
					*	001wxyzabcdef			101wxyz
 | 
				
			||||||
 | 
					*	01wxyzabcdefg			110wxyz
 | 
				
			||||||
 | 
					*	1wxyzabcdefgh			111wxyz
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* Each biased linear code has a leading 1 which identifies the segment
 | 
				
			||||||
 | 
					* number. The value of the segment number is equal to 7 minus the number
 | 
				
			||||||
 | 
					* of leading 0's. The quantization interval is directly available as the
 | 
				
			||||||
 | 
					* four bits wxyz.  * The trailing bits (a - h) are ignored.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* Ordinarily the complement of the resulting code word is used for
 | 
				
			||||||
 | 
					* transmission, and so the code word is complemented before it is returned.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					* For further information see John C. Bellamy's Digital Telephony, 1982,
 | 
				
			||||||
 | 
					* John Wiley & Sons, pps 98-111 and 472-476.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					linear2ulaw(
 | 
				
			||||||
 | 
					   short pcm_val)	/* 2's complement (16-bit range) */
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short         mask;
 | 
				
			||||||
 | 
					   short	 seg;
 | 
				
			||||||
 | 
					   unsigned char uval;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Get the sign and the magnitude of the value. */
 | 
				
			||||||
 | 
					   pcm_val = pcm_val >> 2;
 | 
				
			||||||
 | 
					   if (pcm_val < 0) {
 | 
				
			||||||
 | 
					      pcm_val = -pcm_val;
 | 
				
			||||||
 | 
					      mask = 0x7F;
 | 
				
			||||||
 | 
					   } else {
 | 
				
			||||||
 | 
					      mask = 0xFF;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   if ( pcm_val > CLIP ) pcm_val = CLIP;		/* clip the magnitude */
 | 
				
			||||||
 | 
					   pcm_val += (BIAS >> 2);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Convert the scaled magnitude to segment number. */
 | 
				
			||||||
 | 
					   seg = search(pcm_val, seg_uend, 8);
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /*
 | 
				
			||||||
 | 
					   * Combine the sign, segment, quantization bits;
 | 
				
			||||||
 | 
					   * and complement the code word.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					   if (seg >= 8)		/* out of range, return maximum value. */
 | 
				
			||||||
 | 
					      return (unsigned char) (0x7F ^ mask);
 | 
				
			||||||
 | 
					   else {
 | 
				
			||||||
 | 
					      uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
 | 
				
			||||||
 | 
					      return (uval ^ mask);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * First, a biased linear code is derived from the code word. An unbiased
 | 
				
			||||||
 | 
					 * output can then be obtained by subtracting 33 from the biased code.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note that this function expects to be passed the complement of the
 | 
				
			||||||
 | 
					 * original code word. This is in keeping with ISDN conventions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					short
 | 
				
			||||||
 | 
					ulaw2linear(
 | 
				
			||||||
 | 
					   unsigned char	u_val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   short t;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /* Complement to obtain normal u-law value. */
 | 
				
			||||||
 | 
					   u_val = ~u_val;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   /*
 | 
				
			||||||
 | 
					    * Extract and bias the quantization bits. Then
 | 
				
			||||||
 | 
					    * shift up by the segment number and subtract out the bias.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					   t = ((u_val & QUANT_MASK) << 3) + BIAS;
 | 
				
			||||||
 | 
					   t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A-law to u-law conversion */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					alaw2ulaw(
 | 
				
			||||||
 | 
					   unsigned char	aval)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   aval &= 0xff;
 | 
				
			||||||
 | 
					   return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
 | 
				
			||||||
 | 
						   (0x7F ^ _a2u[aval ^ 0x55]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* u-law to A-law conversion */
 | 
				
			||||||
 | 
					unsigned char
 | 
				
			||||||
 | 
					ulaw2alaw(
 | 
				
			||||||
 | 
					   unsigned char	uval)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   uval &= 0xff;
 | 
				
			||||||
 | 
					   return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
 | 
				
			||||||
 | 
								   (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ---------- end of g711.c ----------------------------------------------------- */
 | 
				
			||||||
							
								
								
									
										27
									
								
								contrib/simcom2rtp/g711.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contrib/simcom2rtp/g711.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * g711.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * u-law, A-law and linear PCM conversions.
 | 
				
			||||||
 | 
					 * Source: http://www.speech.kth.se/cost250/refsys/latest/src/g711.h
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _G711_H_
 | 
				
			||||||
 | 
					#define _G711_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned char	linear2alaw(short pcm_val);
 | 
				
			||||||
 | 
					short		    alaw2linear(unsigned char a_val);
 | 
				
			||||||
 | 
					unsigned char	linear2ulaw(short pcm_val);
 | 
				
			||||||
 | 
					short		    ulaw2linear(unsigned char u_val);
 | 
				
			||||||
 | 
					unsigned char	alaw2ulaw(unsigned char aval);
 | 
				
			||||||
 | 
					unsigned char	ulaw2alaw(unsigned char uval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _G711_H_ */
 | 
				
			||||||
							
								
								
									
										102
									
								
								contrib/simcom2rtp/g711_table.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								contrib/simcom2rtp/g711_table.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					#ifndef G711_TABLE_H
 | 
				
			||||||
 | 
					#define G711_TABLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 16384 entries per table (16 bit) */
 | 
				
			||||||
 | 
					unsigned char linear_to_alaw[65536];
 | 
				
			||||||
 | 
					unsigned char linear_to_ulaw[65536];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 16384 entries per table (8 bit) */
 | 
				
			||||||
 | 
					unsigned short alaw_to_linear[256];
 | 
				
			||||||
 | 
					unsigned short ulaw_to_linear[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void build_linear_to_xlaw_table(unsigned char *linear_to_xlaw,
 | 
				
			||||||
 | 
					                                       unsigned char (*linear2xlaw)(short))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i<65536;i++){
 | 
				
			||||||
 | 
					        linear_to_xlaw[i] = linear2xlaw((short) i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void build_xlaw_to_linear_table(unsigned short *xlaw_to_linear,
 | 
				
			||||||
 | 
					                                       short (*xlaw2linear)(unsigned char))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i<256;i++){
 | 
				
			||||||
 | 
					        xlaw_to_linear[i] = (unsigned short) xlaw2linear(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void pcm16_to_xlaw(unsigned char *linear_to_xlaw, int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    const unsigned short *s_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s_samples = (const unsigned short *)src_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i < src_length / 2; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        dst_samples[i] = linear_to_xlaw[s_samples[i]];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void xlaw_to_pcm16(unsigned short *xlaw_to_linear, int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    unsigned char *s_samples;
 | 
				
			||||||
 | 
					    unsigned short *d_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s_samples = (unsigned char *) src_samples;
 | 
				
			||||||
 | 
					    d_samples = (unsigned short *)dst_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i=0; i < src_length; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        d_samples[i] = xlaw_to_linear[s_samples[i]];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_alaw(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pcm16_to_xlaw(linear_to_alaw, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_ulaw(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pcm16_to_xlaw(linear_to_ulaw, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void alaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    xlaw_to_pcm16(alaw_to_linear, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ulaw_to_pcm16(int src_length, const char *src_samples, char *dst_samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    xlaw_to_pcm16(ulaw_to_linear, src_length, src_samples, dst_samples);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_alaw_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_linear_to_xlaw_table(linear_to_alaw, linear2alaw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_ulaw_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_linear_to_xlaw_table(linear_to_ulaw, linear2ulaw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void alaw_pcm16_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_xlaw_to_linear_table(alaw_to_linear, alaw2linear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ulaw_pcm16_tableinit()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    build_xlaw_to_linear_table(ulaw_to_linear, ulaw2linear);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // G711_TABLE_H
 | 
				
			||||||
							
								
								
									
										14
									
								
								contrib/simcom2rtp/g711_table.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								contrib/simcom2rtp/g711_table.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef G711_TABLE_H
 | 
				
			||||||
 | 
					#define G711_TABLE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_to_alaw(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void pcm16_to_ulaw(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void alaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					void ulaw_to_pcm16(int length, const char *src_samples, char *dst_samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pcm16_alaw_tableinit();
 | 
				
			||||||
 | 
					void pcm16_ulaw_tableinit();
 | 
				
			||||||
 | 
					void alaw_pcm16_tableinit();
 | 
				
			||||||
 | 
					void ulaw_pcm16_tableinit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // G711_TABLE_H
 | 
				
			||||||
							
								
								
									
										218
									
								
								contrib/simcom2rtp/simcom2rtp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								contrib/simcom2rtp/simcom2rtp.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,218 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/fsm.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/serial.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/trau/osmo_ortp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "g711.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define RTP_PT_PCMU	0
 | 
				
			||||||
 | 
					#define RTP_PT_PCMA	8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct modem_state {
 | 
				
			||||||
 | 
						struct osmo_fd data_fd;
 | 
				
			||||||
 | 
						struct osmo_rtp_socket *rtp;
 | 
				
			||||||
 | 
						/* queue of linear PCM audio in RTP -> modem direction */
 | 
				
			||||||
 | 
						struct llist_head rtp2modem;
 | 
				
			||||||
 | 
						/* message buffer used if samples insufficient for next RTP frame were received */
 | 
				
			||||||
 | 
						struct msgb *modem2rtp;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *g_tall_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* call-back on received RTP data */
 | 
				
			||||||
 | 
					static void ortp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *payload,
 | 
				
			||||||
 | 
								unsigned int payload_len, uint16_t seq_nr, uint32_t timestamp, bool marker)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* we received a RTP frame */
 | 
				
			||||||
 | 
						struct modem_state *ms = rs->priv;
 | 
				
			||||||
 | 
						struct msgb *msg = msgb_alloc(payload_len*2, "RTP Rx");
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int16_t *out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out = (int16_t *) msgb_put(msg, payload_len*2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (payload_len != 160) {
 | 
				
			||||||
 | 
							fprintf(stderr, "RTP payload length %d != 160, dropping\n", payload_len);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* convert from Alaw to linear PCM (160 -> 320 bytes) */
 | 
				
			||||||
 | 
						for (i = 0; i < payload_len; i++)
 | 
				
			||||||
 | 
							out[i] = alaw2linear(payload[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* append to the write queue */
 | 
				
			||||||
 | 
						msgb_enqueue(&ms->rtp2modem, msg);
 | 
				
			||||||
 | 
						ms->data_fd.when |= OSMO_FD_WRITE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void modem2rtp(struct modem_state *ms, const uint8_t *data, unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const int16_t *data16 = (const int16_t *)data;
 | 
				
			||||||
 | 
						unsigned int samples = len / 2;
 | 
				
			||||||
 | 
						unsigned int offset = 0;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* samples are always 16bit, we cannot read half a sample */
 | 
				
			||||||
 | 
						OSMO_ASSERT((len & 1) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* first complete any pending incomplete RTP frame */
 | 
				
			||||||
 | 
						if (ms->modem2rtp) {
 | 
				
			||||||
 | 
							struct msgb *msg = ms->modem2rtp;
 | 
				
			||||||
 | 
							unsigned int missing_samples = 160 - msgb_length(msg);
 | 
				
			||||||
 | 
							for (i = 0; i < missing_samples; i++) {
 | 
				
			||||||
 | 
								if (i >= samples)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								msgb_put_u8(msg, linear2alaw(data16[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							offset = i;
 | 
				
			||||||
 | 
							if (msgb_length(msg) == 160) {
 | 
				
			||||||
 | 
								osmo_rtp_send_frame_ext(ms->rtp, msgb_data(msg), msgb_length(msg), 160, false);
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* then send as many RTP frames as we have samples */
 | 
				
			||||||
 | 
						for (offset = offset; offset + 160 <= samples; offset += 160) {
 | 
				
			||||||
 | 
							uint8_t buf[160];
 | 
				
			||||||
 | 
							for (i = 0; i < sizeof(buf); i++)
 | 
				
			||||||
 | 
								buf[i] = linear2alaw(data16[offset + i]);
 | 
				
			||||||
 | 
							osmo_rtp_send_frame_ext(ms->rtp, buf, sizeof(buf), 160, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* store remainder in msgb */
 | 
				
			||||||
 | 
						if (offset < samples) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_alloc_c(ms, 160, "modem2rtp");
 | 
				
			||||||
 | 
							OSMO_ASSERT(msg);
 | 
				
			||||||
 | 
							OSMO_ASSERT(len - offset < 160);
 | 
				
			||||||
 | 
							for (i = 0; i < len - offset; i++)
 | 
				
			||||||
 | 
								msgb_put_u8(msg, linear2alaw(data16[offset + i]));
 | 
				
			||||||
 | 
							ms->modem2rtp = msg;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* call back on file descriptor events of the modem DATA ttyUSB device */
 | 
				
			||||||
 | 
					static int modem_data_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct modem_state *ms = ofd->data;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (what & OSMO_FD_READ) {
 | 
				
			||||||
 | 
							/* SIM5360 USB AUDIO Application Note v1.01 states 1600 bytes every 100ms */
 | 
				
			||||||
 | 
							uint8_t rx_buf[1600];
 | 
				
			||||||
 | 
							rc = read(ofd->fd, rx_buf, sizeof(rx_buf));
 | 
				
			||||||
 | 
							OSMO_ASSERT(rc > 0);
 | 
				
			||||||
 | 
							modem2rtp(ms, rx_buf, rc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (what & OSMO_FD_WRITE) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_dequeue(&ms->rtp2modem);
 | 
				
			||||||
 | 
							if (!msg)
 | 
				
			||||||
 | 
								ofd->when &= ~OSMO_FD_WRITE;
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								/* SIM5300 USB AUDIO Application Note v1.01 states 640 bytes every 40ms;
 | 
				
			||||||
 | 
								 * we simply write every RTP frame individually (320 bytes every 20ms) */
 | 
				
			||||||
 | 
								rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
								if (rc != msgb_length(msg))
 | 
				
			||||||
 | 
									fprintf(stderr, "Short write: %d < %u\n", rc, msgb_length(msg));
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int modem_data_open(struct modem_state *ms, const char *basepath)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char fname[PATH_MAX+1];
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the assumption is that the caller provides something like
 | 
				
			||||||
 | 
						 * "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1" */
 | 
				
			||||||
 | 
						snprintf(fname, sizeof(fname), "%s.0-port0", basepath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd = osmo_serial_init(fname, 921600);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "failed to open device '%s': %s\n", fname, strerror(errno));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						osmo_fd_setup(&ms->data_fd, fd, OSMO_FD_READ, modem_data_fd_cb, ms, 0);
 | 
				
			||||||
 | 
						osmo_fd_register(&ms->data_fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct modem_state *modem_create(void *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct modem_state *ms = talloc_zero(ctx, struct modem_state);
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&ms->rtp2modem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms->rtp = osmo_rtp_socket_create(ms, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->rtp);
 | 
				
			||||||
 | 
						osmo_rtp_socket_set_pt(ms->rtp, RTP_PT_PCMA);
 | 
				
			||||||
 | 
						ms->rtp->priv = ms;
 | 
				
			||||||
 | 
						ms->rtp->rx_cb = ortp_rx_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_rtp_socket_bind(ms->rtp, "0.0.0.0", 1111);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osmo_rtp_socket_connect(ms->rtp, "127.0.0.1", 2222);
 | 
				
			||||||
 | 
						//rc = osmo_rtp_socket_autoconnect(ms->rtp);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_rtp_set_source_desc(ms->rtp, "cname", "simcom2rtp", NULL, NULL, NULL,
 | 
				
			||||||
 | 
									 "osmo-simcom2rtp", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_enable_null_tracking();
 | 
				
			||||||
 | 
						g_tall_ctx = talloc_named_const(NULL, 1, "simcom2rtp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_talloc_ctx_init(g_tall_ctx, 0);
 | 
				
			||||||
 | 
						osmo_init_logging2(g_tall_ctx, NULL);
 | 
				
			||||||
 | 
						osmo_fsm_log_timeouts(true);
 | 
				
			||||||
 | 
						osmo_fsm_log_addr(true);
 | 
				
			||||||
 | 
						//osmo_stats_init(g_tall_ctx);
 | 
				
			||||||
 | 
						osmo_rtp_init(g_tall_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct modem_state *ms = modem_create(g_tall_ctx);
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms);
 | 
				
			||||||
 | 
						rc = modem_data_open(ms, "/dev/serial/by-path/pci-0000:00:14.0-usb-0:2:1");
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							osmo_select_main(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,16 +3,9 @@ Description=Osmocom Media Gateway (MGW)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[Service]
 | 
					[Service]
 | 
				
			||||||
Type=simple
 | 
					Type=simple
 | 
				
			||||||
StateDirectory=osmocom
 | 
					 | 
				
			||||||
WorkingDirectory=%S/osmocom
 | 
					 | 
				
			||||||
Restart=always
 | 
					Restart=always
 | 
				
			||||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
					ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
 | 
				
			||||||
RestartSec=2
 | 
					RestartSec=2
 | 
				
			||||||
# CPU scheduling policy:
 | 
					 | 
				
			||||||
CPUSchedulingPolicy=rr
 | 
					 | 
				
			||||||
# For real-time scheduling policies an integer between 1 (lowest priority) and 99 (highest priority):
 | 
					 | 
				
			||||||
CPUSchedulingPriority=1
 | 
					 | 
				
			||||||
# See sched(7) for further details on real-time policies and priorities
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Install]
 | 
					[Install]
 | 
				
			||||||
WantedBy=multi-user.target
 | 
					WantedBy=multi-user.target
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										158
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,161 +1,3 @@
 | 
				
			|||||||
osmo-mgw (1.10.0) unstable; urgency=medium
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Eric ]
 | 
					 | 
				
			||||||
  * adjust mgcp response context
 | 
					 | 
				
			||||||
  * rework message handling
 | 
					 | 
				
			||||||
  * add a lock-free bounded spsc interthread queue
 | 
					 | 
				
			||||||
  * clang-format: remove foreach macros
 | 
					 | 
				
			||||||
  * fix mgcp_conn_free_all ubsan complaints
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Philipp Maier ]
 | 
					 | 
				
			||||||
  * configuration: point out difference between trunk-nr and e1 line nr
 | 
					 | 
				
			||||||
  * mgcp_client: add new codec IUFP as VND.3GPP.IUFP
 | 
					 | 
				
			||||||
  * mgcp_codec: do not differentiate between oa and bwe when comparing codec
 | 
					 | 
				
			||||||
  * mgcp_network: do not try to convert RTCP packets
 | 
					 | 
				
			||||||
  * mgcp_network: fix typo RTPC -> RTCP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Oliver Smith ]
 | 
					 | 
				
			||||||
  * treewide: remove FSF address
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					 | 
				
			||||||
  * mgcp_network.c: Set proper CRC Header for ACK Initialization
 | 
					 | 
				
			||||||
  * cosmetic: Rename variable payload=>payload_type
 | 
					 | 
				
			||||||
  * mgcp_network.c: Fix byte alignment of CRC Header for ACK Initialization
 | 
					 | 
				
			||||||
  * Define mgcp_rtp_end.output_enabled as bool
 | 
					 | 
				
			||||||
  * cosmetic: mgcp_codec.c: Fix typo in comment
 | 
					 | 
				
			||||||
  * Drop unneeded ax_check_compile_flag.m4
 | 
					 | 
				
			||||||
  * Make function amr_is_octet_aligned publicly available
 | 
					 | 
				
			||||||
  * Initial IuUP support using proper FSMs
 | 
					 | 
				
			||||||
  * IuUP: Support RFCI ID != RFCI Index
 | 
					 | 
				
			||||||
  * iuup: Fix caps in logging message
 | 
					 | 
				
			||||||
  * iuup: Check for IuUP Initialization retrans
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Alexander Couzens ]
 | 
					 | 
				
			||||||
  * doc/overview: fix wrong project page link
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Vadim Yanitskiy ]
 | 
					 | 
				
			||||||
  * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
 | 
					 | 
				
			||||||
  * libosmo-mgcp: e1: fix memleaks in e1_recv_cb()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Harald Welte ]
 | 
					 | 
				
			||||||
  * update git URLs (git -> https; gitea)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 28 Jun 2022 18:50:25 +0200
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
osmo-mgw (1.9.0) unstable; urgency=medium
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Harald Welte ]
 | 
					 | 
				
			||||||
  * TOS bits != DSCP
 | 
					 | 
				
			||||||
  * manual: don't define fig-bsc twice
 | 
					 | 
				
			||||||
  * switch from osmo_sock_set_dscp() to OSMO_SOCK_F_DSCP()
 | 
					 | 
				
			||||||
  * mgw: Add support for setting socket priority from VTY
 | 
					 | 
				
			||||||
  * manual: Include QoS chapter and add osmo-mgw specific example
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Keith ]
 | 
					 | 
				
			||||||
  * Add vty command 'show mgcp active'
 | 
					 | 
				
			||||||
  * Log some useful messages at ERROR/INFO instead of DEBUG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Neels Hofmeyr ]
 | 
					 | 
				
			||||||
  * send DLCX only once
 | 
					 | 
				
			||||||
  * tweak termination DLCX log msg
 | 
					 | 
				
			||||||
  * add osmo_mgcpc_ep_ci_get_remote_rtp_info()
 | 
					 | 
				
			||||||
  * check_rtp_destin(): clarify log msg
 | 
					 | 
				
			||||||
  * mgcp_client_fsm delete: set mgcp_client as ctx, not NULL
 | 
					 | 
				
			||||||
  * mgcp_client_endpoint_fsm: on term, still let conns wait for DLCX OK
 | 
					 | 
				
			||||||
  * mgcp_client_fsm: add missing log_subsys
 | 
					 | 
				
			||||||
  * mgcp_client: add logging on received MGCP messages
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Philipp Maier ]
 | 
					 | 
				
			||||||
  * mgcp_network: fix implicit address loopback
 | 
					 | 
				
			||||||
  * mgcp_common, mgcp_udp_send: make parameter buf const
 | 
					 | 
				
			||||||
  * mgcp_network: refactor MGCP_DUMMY_LOAD
 | 
					 | 
				
			||||||
  * mgcp_client: drop nunnecessary else statement
 | 
					 | 
				
			||||||
  * mgcp_client: fix error handling in mgcp message generation
 | 
					 | 
				
			||||||
  * mgcp_protocol: fix loop that sends dummy RTP packets
 | 
					 | 
				
			||||||
  * mgw_main: fix loop that resets all endpoints
 | 
					 | 
				
			||||||
  * mgcp_trunk: drop ws line
 | 
					 | 
				
			||||||
  * mgcp_ratectr: drop ws line
 | 
					 | 
				
			||||||
  * mgcp_ratectr: fix sourcecode formatting
 | 
					 | 
				
			||||||
  * mgcp_trunk: add value string for trunk type.
 | 
					 | 
				
			||||||
  * mgcp_ratectr: refactor rate counter and set group name
 | 
					 | 
				
			||||||
  * mgcp_protocol: forward declare mgcp_endpoint
 | 
					 | 
				
			||||||
  * mgcp_endp: make wildcarded detection separate
 | 
					 | 
				
			||||||
  * mgcp_protocol: refactor request handler array
 | 
					 | 
				
			||||||
  * mgcp_trunk: use unsigned int instead of int as trunk_nr
 | 
					 | 
				
			||||||
  * mgcp_protocol: refactor MGCP request handling
 | 
					 | 
				
			||||||
  * mgcp_ratectr: add stats items to monitor trunk usage
 | 
					 | 
				
			||||||
  * mgcp_msg: add trunk parameter to mgcp_check_param for logging
 | 
					 | 
				
			||||||
  * mgcp_protocol: refactor function create_response_with_sdp
 | 
					 | 
				
			||||||
  * mgcp_protocol: add support for wildcarded DLCX
 | 
					 | 
				
			||||||
  * remove struct member wildcarded_req from struct mgcp_endpoint
 | 
					 | 
				
			||||||
  * mgcp_lient: remove unsubstantial FIXME note
 | 
					 | 
				
			||||||
  * mgcp_protocol: assert endp when it becomes mandatory
 | 
					 | 
				
			||||||
  * mgcp_trunk: check MGW domain name earlier
 | 
					 | 
				
			||||||
  * mgcp_ratectr: add stats items to monitor trunk usage
 | 
					 | 
				
			||||||
  * mgcp_client: fix typo Initalize -> Initialize
 | 
					 | 
				
			||||||
  * mgcp_protocol: get rid of policy_cb and change_cb
 | 
					 | 
				
			||||||
  * mgcp_ratectr: do not set talloc destructor on library allocated item
 | 
					 | 
				
			||||||
  * mgcp_client: allow to reset endpoints on startup
 | 
					 | 
				
			||||||
  * mgcp_client_vty: remove unnecessary checks
 | 
					 | 
				
			||||||
  * mgcp_client: do not print (null) when address is ANY
 | 
					 | 
				
			||||||
  * mgcp_client: refactor function init_socket
 | 
					 | 
				
			||||||
  * libosmo-mgcp-client: extend the mgcp_client for MGW pooling
 | 
					 | 
				
			||||||
  * mgcp_client_vty: add missing docstrings
 | 
					 | 
				
			||||||
  * mgcp_client_vty: add OSMO_ASSERT on pool parameter
 | 
					 | 
				
			||||||
  * mgcp_client_vty: fix docstrings for mgw-pool
 | 
					 | 
				
			||||||
  * mgcp_client_vty: cosmetic: doc string should terminated with \n
 | 
					 | 
				
			||||||
  * mgcp_client_vty: fixing docstring
 | 
					 | 
				
			||||||
  * mgcp_ratectr: remove unusued rate counters
 | 
					 | 
				
			||||||
  * mgcp_client: fix typo in doxygen comment
 | 
					 | 
				
			||||||
  * mgcp_client: add MGW name as logging context
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Pau Espin Pedrol ]
 | 
					 | 
				
			||||||
  * Use new stat item/ctr getter APIs
 | 
					 | 
				
			||||||
  * constify arg in addr_is_any()
 | 
					 | 
				
			||||||
  * Define patch_ssrc as bool type
 | 
					 | 
				
			||||||
  * constify some function arg pointers
 | 
					 | 
				
			||||||
  * mgcp_network.c: Reorder some functions in file
 | 
					 | 
				
			||||||
  * mgcp_send_dummy: Check RTP destination is available before attempt tx
 | 
					 | 
				
			||||||
  * mgw: rx CRCX: Avoid sending dummy rtp if remote address not provided
 | 
					 | 
				
			||||||
  * Fail rx MDCX sendrecv with invalid remote addr
 | 
					 | 
				
			||||||
  * Take into account Marker bit when patching RTP stream
 | 
					 | 
				
			||||||
  * Use DLMGCP instead of DLGLOBAL in log lines
 | 
					 | 
				
			||||||
  * Fix attribute parsing on gcc 11.1.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ neels ]
 | 
					 | 
				
			||||||
  * Revert "mgcp_ratectr: add stats items to monitor trunk usage"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Daniel Willmann ]
 | 
					 | 
				
			||||||
  * contrib/jenkins: Use ASAN for osmo-mgw
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Oliver Smith ]
 | 
					 | 
				
			||||||
  * mgcp_client_vty: add missing NO_STR
 | 
					 | 
				
			||||||
  * Revert "Turn some compiler warnings into errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Eric ]
 | 
					 | 
				
			||||||
  * add vscode stuff to gitignore
 | 
					 | 
				
			||||||
  * configure.ac: fix maybe-uninitialized for clang
 | 
					 | 
				
			||||||
  * fix missing includes and forward declarations
 | 
					 | 
				
			||||||
  * rename do_retransmission
 | 
					 | 
				
			||||||
  * mgcp_sdp: fix potential leak
 | 
					 | 
				
			||||||
  * stats: make sanitizers happy
 | 
					 | 
				
			||||||
  * libosmo-mgcp: cleanup audio codex alloc
 | 
					 | 
				
			||||||
  * libosmo-mgcp: atomic rate counter group indexes
 | 
					 | 
				
			||||||
  * libosmo-mgcp: do not use the default msgb talloc context
 | 
					 | 
				
			||||||
  * globally lock the portrange when trying to grab a port to prep for multithreading
 | 
					 | 
				
			||||||
  * embed strings into structs
 | 
					 | 
				
			||||||
  * adjust talloc context
 | 
					 | 
				
			||||||
  * endp: do not cache cfg pointer
 | 
					 | 
				
			||||||
  * add modified .clang-format
 | 
					 | 
				
			||||||
  * rename strip_epname and find_specific_endpoint and make them available
 | 
					 | 
				
			||||||
  * fix mgcp_conn_free_all
 | 
					 | 
				
			||||||
  * fix up some docstrings that lost their dot
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [ Vadim Yanitskiy ]
 | 
					 | 
				
			||||||
  * libosmo-mgcp: use OSMO_STRLCPY_ARRAY in mgcp_codec_add()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 16 Nov 2021 16:59:21 +0100
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
osmo-mgw (1.8.1) unstable; urgency=medium
 | 
					osmo-mgw (1.8.1) unstable; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * attempt to fix RPM spec file after recent soversion bump
 | 
					  * attempt to fix RPM spec file after recent soversion bump
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,13 +6,13 @@ Build-Depends: debhelper (>=9),
 | 
				
			|||||||
               dh-autoreconf,
 | 
					               dh-autoreconf,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               libosmocore-dev (>= 1.7.0),
 | 
					               libosmocore-dev (>= 1.5.0),
 | 
				
			||||||
               libosmo-netif-dev (>= 1.2.0),
 | 
					               libosmo-netif-dev (>= 1.1.0),
 | 
				
			||||||
               libosmo-abis-dev (>= 1.3.0),
 | 
					               libosmo-abis-dev (>= 1.1.0),
 | 
				
			||||||
               osmo-gsm-manuals-dev (>= 1.3.0)
 | 
					               osmo-gsm-manuals-dev (>= 1.1.0)
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Git: git://git.osmocom.org/osmo-mgw.git
 | 
				
			||||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Vcs-Browser: https://git.osmocom.org/osmo-mgw/
 | 
				
			||||||
Homepage: https://osmocom.org/projects/osmo-mgw
 | 
					Homepage: https://osmocom.org/projects/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw
 | 
					Package: osmo-mgw
 | 
				
			||||||
@@ -21,7 +21,7 @@ Multi-Arch: foreign
 | 
				
			|||||||
Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
					Depends: ${misc:Depends}, ${shlibs:Depends}
 | 
				
			||||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
					Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: libosmo-mgcp-client9
 | 
					Package: libosmo-mgcp-client8
 | 
				
			||||||
Section: libs
 | 
					Section: libs
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
@@ -33,7 +33,7 @@ Package: libosmo-mgcp-client-dev
 | 
				
			|||||||
Section: libdevel
 | 
					Section: libdevel
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Multi-Arch: same
 | 
					Multi-Arch: same
 | 
				
			||||||
Depends: libosmo-mgcp-client9 (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: libosmo-mgcp-client8 (= ${binary:Version}), ${misc:Depends}
 | 
				
			||||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
					Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmo-mgw-doc
 | 
					Package: osmo-mgw-doc
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
					Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
				
			||||||
Upstream-Name: osmo-mgw
 | 
					Upstream-Name: osmo-mgw
 | 
				
			||||||
Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw
 | 
					Source: git://git.osmocom.org/osmo-mgw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Files:     *
 | 
					Files:     *
 | 
				
			||||||
Copyright: 2009-2014 On-Waves
 | 
					Copyright: 2009-2014 On-Waves
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,11 +91,6 @@ the IP related aspects is nearly identical to the configuration of the virtual
 | 
				
			|||||||
trunk. However, it is important that the user assigns one of the E1 line numbers
 | 
					trunk. However, it is important that the user assigns one of the E1 line numbers
 | 
				
			||||||
that were configured under the e1_input node.
 | 
					that were configured under the e1_input node.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NOTE: The endpoint name that is used on MGCP level will include the trunk number,
 | 
					 | 
				
			||||||
not the E1 line number. For simplicity (and compatibility with OsmoBSC) it is
 | 
					 | 
				
			||||||
recommended to use equal numbers for trunk and E1 line. However, if required any
 | 
					 | 
				
			||||||
E1 line can be mapped flexible on any trunk as long as the mapping is bijective.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.Example: A typical configuration with one E1 trunk
 | 
					.Example: A typical configuration with one E1 trunk
 | 
				
			||||||
----
 | 
					----
 | 
				
			||||||
e1_input
 | 
					e1_input
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,8 +107,8 @@ We are planning to add further endpoint types for:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
You can find the OsmoMGW issue tracker and wiki online at
 | 
					You can find the OsmoMGW issue tracker and wiki online at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- https://osmocom.org/projects/osmo-mgw
 | 
					- https://osmocom.org/projects/osmomgw
 | 
				
			||||||
- https://osmocom.org/projects/osmo-mgw/wiki
 | 
					- https://osmocom.org/projects/osmomgw/wiki
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RFC 3435 for MGCP is located at
 | 
					RFC 3435 for MGCP is located at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,11 @@ noinst_HEADERS = \
 | 
				
			|||||||
	mgcp_endp.h \
 | 
						mgcp_endp.h \
 | 
				
			||||||
	mgcp_sdp.h \
 | 
						mgcp_sdp.h \
 | 
				
			||||||
	mgcp_codec.h \
 | 
						mgcp_codec.h \
 | 
				
			||||||
 | 
						mgcp_ctrl.h \
 | 
				
			||||||
	mgcp_trunk.h \
 | 
						mgcp_trunk.h \
 | 
				
			||||||
	debug.h \
 | 
						debug.h \
 | 
				
			||||||
	mgcp_ratectr.h \
 | 
						mgcp_ratectr.h \
 | 
				
			||||||
	mgcp_e1.h \
 | 
						mgcp_e1.h \
 | 
				
			||||||
	mgcp_network.h \
 | 
						mgcp_network.h \
 | 
				
			||||||
	mgcp_protocol.h \
 | 
						mgcp_protocol.h \
 | 
				
			||||||
	mgcp_iuup.h \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,6 @@
 | 
				
			|||||||
enum {
 | 
					enum {
 | 
				
			||||||
	DRTP,
 | 
						DRTP,
 | 
				
			||||||
	DE1,
 | 
						DE1,
 | 
				
			||||||
	DOSMUX,
 | 
					 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,6 @@
 | 
				
			|||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_common.h>
 | 
					#include <osmocom/mgcp/mgcp_common.h>
 | 
				
			||||||
#include <osmocom/mgcp/osmux.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <arpa/inet.h>
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
@@ -157,26 +156,24 @@ struct mgcp_config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	enum mgcp_role role;
 | 
						enum mgcp_role role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						/* osmux translator: 0 means disabled, 1 means enabled */
 | 
				
			||||||
		/* Osmux usage policy: */
 | 
						int osmux;
 | 
				
			||||||
		enum osmux_usage usage;
 | 
					 | 
				
			||||||
	/* addr to bind the server to */
 | 
						/* addr to bind the server to */
 | 
				
			||||||
		char *local_addr_v4;
 | 
						char osmux_addr[INET6_ADDRSTRLEN];
 | 
				
			||||||
		char *local_addr_v6;
 | 
						/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
 | 
				
			||||||
		/* osmux port */
 | 
						 * the osmux socket is already initialized.
 | 
				
			||||||
		uint16_t local_port;
 | 
						 */
 | 
				
			||||||
		/* The osmux socket is allocated on demand (1st time used).
 | 
						int osmux_init;
 | 
				
			||||||
		* This tells us if the osmux socket is already initialized.  */
 | 
					 | 
				
			||||||
		bool initialized;
 | 
					 | 
				
			||||||
	/* osmux batch factor: from 1 to 4 maximum */
 | 
						/* osmux batch factor: from 1 to 4 maximum */
 | 
				
			||||||
		int batch_factor;
 | 
						int osmux_batch;
 | 
				
			||||||
	/* osmux batch size (in bytes) */
 | 
						/* osmux batch size (in bytes) */
 | 
				
			||||||
		int batch_size;
 | 
						int osmux_batch_size;
 | 
				
			||||||
		/* Pad circuit with dummy AMR frames if no payload to transmit is available */
 | 
						/* osmux port */
 | 
				
			||||||
		bool dummy_padding;
 | 
						uint16_t osmux_port;
 | 
				
			||||||
		/* Whether peer is behind NAT (Retrieve remote addr from 1st received Osmux packet) */
 | 
						/* Pad circuit with dummy messages until we see the first voice
 | 
				
			||||||
		bool peer_behind_nat;
 | 
						 * message.
 | 
				
			||||||
	} osmux;
 | 
						 */
 | 
				
			||||||
 | 
						uint16_t osmux_dummy;
 | 
				
			||||||
	/* domain name of the media gateway */
 | 
						/* domain name of the media gateway */
 | 
				
			||||||
	char domain[255+1];
 | 
						char domain[255+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,4 +207,4 @@ int mgcp_send_reset_all(struct mgcp_config *cfg);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
					int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port, uint8_t dscp,
 | 
				
			||||||
		     uint8_t prio);
 | 
							     uint8_t prio);
 | 
				
			||||||
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len);
 | 
					int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,5 +17,3 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn);
 | 
				
			|||||||
int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
					int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst, int payload_type);
 | 
				
			||||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
					const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
 | 
				
			||||||
								const char *subtype_name, unsigned int match_nr);
 | 
													const char *subtype_name, unsigned int match_nr);
 | 
				
			||||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec);
 | 
					 | 
				
			||||||
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,6 @@
 | 
				
			|||||||
#include <osmocom/mgcp/osmux.h>
 | 
					#include <osmocom/mgcp/osmux.h>
 | 
				
			||||||
#include <osmocom/core/linuxlist.h>
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <osmocom/gsm/iuup.h>
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
					#define LOGPCONN(conn, cat, level, fmt, args...) \
 | 
				
			||||||
@@ -46,8 +45,8 @@ LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
 | 
				
			|||||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
					/* Specific rtp connection type (see struct mgcp_conn_rtp) */
 | 
				
			||||||
enum mgcp_conn_rtp_type {
 | 
					enum mgcp_conn_rtp_type {
 | 
				
			||||||
	MGCP_RTP_DEFAULT	= 0,
 | 
						MGCP_RTP_DEFAULT	= 0,
 | 
				
			||||||
	MGCP_RTP_OSMUX,
 | 
						MGCP_OSMUX_BSC,
 | 
				
			||||||
	MGCP_RTP_IUUP,
 | 
						MGCP_OSMUX_BSC_NAT,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
					/*! Connection type, specifies which member of the union "u" in mgcp_conn
 | 
				
			||||||
@@ -79,31 +78,22 @@ struct mgcp_conn_rtp {
 | 
				
			|||||||
	struct {
 | 
						struct {
 | 
				
			||||||
		/* Osmux state: disabled, activating, active */
 | 
							/* Osmux state: disabled, activating, active */
 | 
				
			||||||
		enum osmux_state state;
 | 
							enum osmux_state state;
 | 
				
			||||||
		/* Is local_cid holding valid data? is it allocated from pool? */
 | 
							/* Is cid holding valid data? is it allocated from pool? */
 | 
				
			||||||
		bool local_cid_allocated;
 | 
							bool cid_allocated;
 | 
				
			||||||
		/* Allocated local Osmux circuit ID for this conn */
 | 
							/* Allocated Osmux circuit ID for this conn */
 | 
				
			||||||
		uint8_t local_cid;
 | 
							uint8_t cid;
 | 
				
			||||||
		/* Is remote_cid holding valid data? was it already received from client? */
 | 
							/* handle to batch messages */
 | 
				
			||||||
		bool remote_cid_present;
 | 
					 | 
				
			||||||
		/* Received remote Osmux circuit ID for this conn */
 | 
					 | 
				
			||||||
		uint8_t remote_cid;
 | 
					 | 
				
			||||||
		/* handle to batch messages, shared (refcounted) among several conns */
 | 
					 | 
				
			||||||
		struct osmux_in_handle *in;
 | 
							struct osmux_in_handle *in;
 | 
				
			||||||
		/* handle to unbatch messages, one allocated and owned per conn */
 | 
							/* handle to unbatch messages */
 | 
				
			||||||
		struct osmux_out_handle *out;
 | 
							struct osmux_out_handle out;
 | 
				
			||||||
		/* statistics: */
 | 
							/* statistics */
 | 
				
			||||||
		struct rate_ctr_group *ctrg;
 | 
							struct {
 | 
				
			||||||
 | 
								uint32_t chunks;
 | 
				
			||||||
 | 
								uint32_t octets;
 | 
				
			||||||
 | 
							} stats;
 | 
				
			||||||
	} osmux;
 | 
						} osmux;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct {
 | 
						struct rate_ctr_group *rate_ctr_group;
 | 
				
			||||||
		struct osmo_iuup_instance *iui;
 | 
					 | 
				
			||||||
		bool active_init; /* true: Send IuUP Init */
 | 
					 | 
				
			||||||
		int rfci_id_no_data; /* RFCI Id for RFCI NO_DATA (-1 if not available) */
 | 
					 | 
				
			||||||
		bool configured;
 | 
					 | 
				
			||||||
		struct osmo_iuup_rnl_prim *init_ind;
 | 
					 | 
				
			||||||
	} iuup;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct rate_ctr_group *ctrg;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! MGCP connection (untyped) */
 | 
					/*! MGCP connection (untyped) */
 | 
				
			||||||
@@ -163,7 +153,7 @@ static const struct rate_ctr_desc mgcp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
						[RTP_OCTETS_RX_CTR] = {"rtp:octets_rx", "Inbound rtp octets."},
 | 
				
			||||||
	[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
						[RTP_PACKETS_TX_CTR] = {"rtp:packets_tx", "Outbound rtp packets."},
 | 
				
			||||||
	[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
						[RTP_OCTETS_TX_CTR] = {"rtp:octets_tx", "Outbound rtp octets."},
 | 
				
			||||||
	[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "Dropped rtp packets."}
 | 
						[RTP_DROPPED_PACKETS_CTR] = {"rtp:dropped", "dropped rtp packets."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
					/* Aggregated RTP connection stats. These are updated when an RTP connection is freed.
 | 
				
			||||||
@@ -181,55 +171,9 @@ static const struct rate_ctr_desc all_rtp_conn_rate_ctr_desc[] = {
 | 
				
			|||||||
	[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
						[RTP_NUM_CONNECTIONS] = {"all_rtp:num_closed_conns", "Total number of rtp connections closed."}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Osmux connection related counters */
 | 
					 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
	OSMUX_CHUNKS_RX_CTR,
 | 
					 | 
				
			||||||
	OSMUX_OCTETS_RX_CTR,
 | 
					 | 
				
			||||||
	OSMUX_RTP_PACKETS_TX_CTR,
 | 
					 | 
				
			||||||
	OSMUX_RTP_PACKETS_TX_DROPPED_CTR,
 | 
					 | 
				
			||||||
	OSMUX_AMR_OCTETS_TX_CTR,
 | 
					 | 
				
			||||||
	/* Only available in global stats: */
 | 
					 | 
				
			||||||
	OSMUX_NUM_CONNECTIONS,
 | 
					 | 
				
			||||||
	OSMUX_PACKETS_RX_CTR,
 | 
					 | 
				
			||||||
	OSMUX_PACKETS_TX_CTR,
 | 
					 | 
				
			||||||
	OSMUX_DROPPED_PACKETS_CTR,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* RTP per-connection statistics. Instances of the corresponding rate counter group
 | 
					 | 
				
			||||||
 * exist for the lifetime of an RTP connection.
 | 
					 | 
				
			||||||
 * Must be kept in sync with all_rtp_conn_rate_ctr_desc below */
 | 
					 | 
				
			||||||
static const struct rate_ctr_desc mgcp_conn_osmux_rate_ctr_desc[] = {
 | 
					 | 
				
			||||||
	[OSMUX_CHUNKS_RX_CTR] = {"osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
					 | 
				
			||||||
	[OSMUX_OCTETS_RX_CTR] = {"osmux:octets_rx", "Inbound Osmux octets."},
 | 
					 | 
				
			||||||
	[OSMUX_RTP_PACKETS_TX_CTR] = {"osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
					 | 
				
			||||||
	[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
					 | 
				
			||||||
	[OSMUX_AMR_OCTETS_TX_CTR] = {"osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Aggregated Osmux connection stats. These are updated when an Osmux connection is freed.
 | 
					 | 
				
			||||||
 * Must be kept in sync with mgcp_conn_osmux_rate_ctr_desc above */
 | 
					 | 
				
			||||||
static const struct rate_ctr_desc all_osmux_conn_rate_ctr_desc[] = {
 | 
					 | 
				
			||||||
	[OSMUX_CHUNKS_RX_CTR] = {"all_osmux:chunks_rx", "Inbound Osmux chunks."},
 | 
					 | 
				
			||||||
	[OSMUX_OCTETS_RX_CTR] = {"all_osmux:octets_rx", "Inbound Osmux octets."},
 | 
					 | 
				
			||||||
	[OSMUX_RTP_PACKETS_TX_CTR] = {"all_osmux:rtp_packets_tx", "Tx outbound RTP packets to encode as Osmux."},
 | 
					 | 
				
			||||||
	[OSMUX_RTP_PACKETS_TX_DROPPED_CTR] = {"all_osmux:rtp_packets_tx_dropped", "Dropped Tx outbound RTP packets to encode as Osmux."},
 | 
					 | 
				
			||||||
	[OSMUX_AMR_OCTETS_TX_CTR] = {"all_osmux:amr_octets_tx", "Tx outbound AMD payload octets."},
 | 
					 | 
				
			||||||
	/* These last counters below do not exist in per-connection stats, only here: */
 | 
					 | 
				
			||||||
	[OSMUX_NUM_CONNECTIONS] = {"all_osmux:num_closed_conns", "Total number of osmux connections closed."},
 | 
					 | 
				
			||||||
	[OSMUX_PACKETS_RX_CTR] = {"all_osmux:packets_rx", "Total inbound UDP/Osmux packets."},
 | 
					 | 
				
			||||||
	[OSMUX_PACKETS_TX_CTR] = {"all_osmux:packets_tx", "Total outbound UDP/Osmux packets."},
 | 
					 | 
				
			||||||
	[OSMUX_DROPPED_PACKETS_CTR] = {"all_osmux:dropped_packets", "Dropped outbound UDP/Osmux packets."}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					/* Was conn configured to handle Osmux? */
 | 
				
			||||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
					static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
 | 
				
			||||||
	return conn->type == MGCP_RTP_OSMUX;
 | 
						return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Was conn configured to handle Osmux? */
 | 
					 | 
				
			||||||
static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return conn->type == MGCP_RTP_IUUP;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
					struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,7 @@
 | 
				
			|||||||
/* IuUP connection functionalitites */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 * All Rights Reserved
 | 
					 * All Rights Reserved
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Author: Pau Espin Pedrol
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 * 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
 | 
					 * 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
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
@@ -20,14 +16,9 @@
 | 
				
			|||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
				
			||||||
 | 
					                                             const char *bind_addr, uint16_t port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp);
 | 
					 | 
				
			||||||
void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp);
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg);
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg);
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp);
 | 
					 | 
				
			||||||
@@ -40,13 +40,8 @@ LOGP(cat, level, "endpoint:%s " fmt, \
 | 
				
			|||||||
     endp ? endp->name : "none", \
 | 
					     endp ? endp->name : "none", \
 | 
				
			||||||
     ## args)
 | 
					     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum rtp_proto {
 | 
					 | 
				
			||||||
	MGCP_PROTO_RTP,
 | 
					 | 
				
			||||||
	MGCP_PROTO_RTCP,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct osmo_rtp_msg_ctx {
 | 
					struct osmo_rtp_msg_ctx {
 | 
				
			||||||
	enum rtp_proto proto;
 | 
						int proto;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn_src;
 | 
						struct mgcp_conn_rtp *conn_src;
 | 
				
			||||||
	struct osmo_sockaddr *from_addr;
 | 
						struct osmo_sockaddr *from_addr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* The following constant defines an RTP dummy payload that is used for
 | 
					/* The following constant defines an RTP dummy payload that is used for
 | 
				
			||||||
 * "UDP Hole Punching" (NAT) */
 | 
					 * "UDP Hole Punching" (NAT) */
 | 
				
			||||||
#define MGCP_DUMMY_LOAD 0x23
 | 
					static const char rtp_dummy_payload[] = { 0x23 };
 | 
				
			||||||
static const char rtp_dummy_payload[] = { MGCP_DUMMY_LOAD };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the data in a given message buffer matches the rtp dummy payload
 | 
					/* Check if the data in a given message buffer matches the rtp dummy payload
 | 
				
			||||||
 * defined above */
 | 
					 * defined above */
 | 
				
			||||||
@@ -71,6 +70,8 @@ struct mgcp_rtp_state {
 | 
				
			|||||||
	 * data is just re-used) */
 | 
						 * data is just re-used) */
 | 
				
			||||||
	uint16_t alt_rtp_tx_sequence;
 | 
						uint16_t alt_rtp_tx_sequence;
 | 
				
			||||||
	uint32_t alt_rtp_tx_ssrc;
 | 
						uint32_t alt_rtp_tx_ssrc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_rtp_codec {
 | 
					struct mgcp_rtp_codec {
 | 
				
			||||||
@@ -93,7 +94,7 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	struct osmo_sockaddr addr;
 | 
						struct osmo_sockaddr addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* in network byte order */
 | 
						/* in network byte order */
 | 
				
			||||||
	int rtcp_port;
 | 
						int rtp_port, rtcp_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* currently selected audio codec */
 | 
						/* currently selected audio codec */
 | 
				
			||||||
	struct mgcp_rtp_codec *codec;
 | 
						struct mgcp_rtp_codec *codec;
 | 
				
			||||||
@@ -109,8 +110,8 @@ struct mgcp_rtp_end {
 | 
				
			|||||||
	uint32_t packet_duration_ms;
 | 
						uint32_t packet_duration_ms;
 | 
				
			||||||
	int maximum_packet_time; /* -1: not set */
 | 
						int maximum_packet_time; /* -1: not set */
 | 
				
			||||||
	char *fmtp_extra;
 | 
						char *fmtp_extra;
 | 
				
			||||||
	/* are we transmitting packets (true) or dropping (false) outbound packets */
 | 
						/* are we transmitting packets (1) or dropping (0) outbound packets */
 | 
				
			||||||
	bool output_enabled;
 | 
						int output_enabled;
 | 
				
			||||||
	/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
						/* FIXME: This parameter can be set + printed, but is nowhere used! */
 | 
				
			||||||
	int force_output_ptime;
 | 
						int force_output_ptime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -157,7 +158,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
			  struct mgcp_rtp_state *state,
 | 
								  struct mgcp_rtp_state *state,
 | 
				
			||||||
			  struct mgcp_rtp_end *rtp_end,
 | 
								  struct mgcp_rtp_end *rtp_end,
 | 
				
			||||||
			  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
								  struct osmo_sockaddr *addr, struct msgb *msg);
 | 
				
			||||||
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
					void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* payload processing default functions */
 | 
					/* payload processing default functions */
 | 
				
			||||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
					int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
 | 
				
			||||||
@@ -176,12 +177,3 @@ void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
 | 
				
			|||||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
					void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
 | 
				
			||||||
			const uint16_t seq, const int32_t transit,
 | 
								const uint16_t seq, const int32_t transit,
 | 
				
			||||||
			const uint32_t ssrc, const bool marker_bit);
 | 
								const uint32_t ssrc, const bool marker_bit);
 | 
				
			||||||
 | 
					 | 
				
			||||||
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
				 int id, int inc);
 | 
					 | 
				
			||||||
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					 | 
				
			||||||
				 int id);
 | 
					 | 
				
			||||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg);
 | 
					 | 
				
			||||||
uint32_t mgcp_get_current_ts(unsigned codec_rate);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg, bool target_is_oa);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,8 +80,6 @@ struct mgcp_ratectr_trunk {
 | 
				
			|||||||
	struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
						struct rate_ctr_group *mgcp_dlcx_ctr_group;
 | 
				
			||||||
	/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
						/* Rate counter group which aggregates stats of individual RTP connections. */
 | 
				
			||||||
	struct rate_ctr_group *all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_rtp_conn_stats;
 | 
				
			||||||
	/* Rate counter group which aggregates stats of individual Osmux connections. */
 | 
					 | 
				
			||||||
	struct rate_ctr_group *all_osmux_conn_stats;
 | 
					 | 
				
			||||||
	/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
						/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
 | 
				
			||||||
	struct rate_ctr_group *e1_stats;
 | 
						struct rate_ctr_group *e1_stats;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,52 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					 | 
				
			||||||
 * All Rights Reserved
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Author: Eric Wild
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <stdatomic.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct spsc {
 | 
					 | 
				
			||||||
	atomic_uint readptr;
 | 
					 | 
				
			||||||
	atomic_uint writeptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int efd_r, efd_w; /* eventfds used to block/notify readers/writers */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int count;
 | 
					 | 
				
			||||||
	int size_per_buf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *buf; /* buffer size count*size_per_buf */
 | 
					 | 
				
			||||||
	uintptr_t data[0]; /* count sized array of pointers to size_per_buf chunks in buf array*/
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct qchan {
 | 
					 | 
				
			||||||
	struct spsc *a;
 | 
					 | 
				
			||||||
	struct spsc *b;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool spsc_push(struct spsc *q, void *elem);
 | 
					 | 
				
			||||||
bool spsc_pop(struct spsc *q, void *elem);
 | 
					 | 
				
			||||||
ssize_t spsc_prep_pop(struct spsc *q);
 | 
					 | 
				
			||||||
int spsc_get_a_rdfd(struct qchan *q);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct qchan spsc_chan_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf);
 | 
					 | 
				
			||||||
struct qchan spsc_chan_init_ex(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr_a,
 | 
					 | 
				
			||||||
			       bool blockw_a, bool blockr_b, bool blockw_b);
 | 
					 | 
				
			||||||
void spsc_chan_close(struct qchan *q);
 | 
					 | 
				
			||||||
@@ -1,22 +1,25 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/netif/osmux.h>
 | 
					#include <osmocom/netif/osmux.h>
 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					struct mgcp_conn_rtp;
 | 
				
			||||||
struct mgcp_trunk;
 | 
					 | 
				
			||||||
struct mgcp_endpoint;
 | 
					 | 
				
			||||||
struct mgcp_conn_rtp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int osmux_init(struct mgcp_trunk *trunk);
 | 
					#define OSMUX_PORT	1984
 | 
				
			||||||
int osmux_init_conn(struct mgcp_conn_rtp *conn);
 | 
					
 | 
				
			||||||
int conn_osmux_enable(struct mgcp_conn_rtp *conn);
 | 
					enum {
 | 
				
			||||||
 | 
						OSMUX_ROLE_BSC = 0,
 | 
				
			||||||
 | 
						OSMUX_ROLE_BSC_NAT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int osmux_init(int role, struct mgcp_config *cfg);
 | 
				
			||||||
 | 
					int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
 | 
				
			||||||
 | 
							      struct osmo_sockaddr *addr, uint16_t port);
 | 
				
			||||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
					void conn_osmux_disable(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int conn_osmux_event_rx_crcx_mdcx(struct mgcp_conn_rtp *conn);
 | 
					int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
 | 
				
			||||||
int conn_osmux_send_rtp(struct mgcp_conn_rtp *conn, struct msgb *msg);
 | 
					void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
 | 
				
			||||||
int osmux_send_dummy(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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
					void osmux_cid_pool_get(uint8_t osmux_cid);
 | 
				
			||||||
int osmux_cid_pool_get_next(void);
 | 
					int osmux_cid_pool_get_next(void);
 | 
				
			||||||
@@ -26,14 +29,10 @@ int osmux_cid_pool_count_used(void);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum osmux_state {
 | 
					enum osmux_state {
 | 
				
			||||||
	OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
						OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
 | 
				
			||||||
	OSMUX_STATE_ACTIVATING,   /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref conn_osmux_enable. */
 | 
						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 conn_osmux_enable and can process frames */
 | 
						OSMUX_STATE_ENABLED,	  /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct value_string osmux_state_strs[];
 | 
					 | 
				
			||||||
static inline const char *osmux_state_str(enum osmux_state val)
 | 
					 | 
				
			||||||
{ return get_value_string(osmux_state_strs, val); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum osmux_usage {
 | 
					enum osmux_usage {
 | 
				
			||||||
	OSMUX_USAGE_OFF = 0,
 | 
						OSMUX_USAGE_OFF = 0,
 | 
				
			||||||
	OSMUX_USAGE_ON = 1,
 | 
						OSMUX_USAGE_ON = 1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
					/* See also: RFC 3435, chapter 3.5 Transmission over UDP */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
					#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT NULL /* INADDR(6)_ANY */
 | 
				
			||||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
 | 
					#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
					#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
 | 
				
			||||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
					#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,7 +49,6 @@ enum mgcp_codecs {
 | 
				
			|||||||
	CODEC_GSMHR_8000_1 = 111,
 | 
						CODEC_GSMHR_8000_1 = 111,
 | 
				
			||||||
	CODEC_AMR_8000_1 = 112,
 | 
						CODEC_AMR_8000_1 = 112,
 | 
				
			||||||
	CODEC_AMRWB_16000_1 = 113,
 | 
						CODEC_AMRWB_16000_1 = 113,
 | 
				
			||||||
	CODEC_IUFP = 96,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
/* Note: when new codec types are added, the corresponding value strings
 | 
					/* Note: when new codec types are added, the corresponding value strings
 | 
				
			||||||
 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
					 * in mgcp_client.c (codec_table) must be updated as well. Enumerations
 | 
				
			||||||
@@ -140,7 +139,7 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
 | 
				
			|||||||
struct mgcp_client *mgcp_client_init(void *ctx,
 | 
					struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			||||||
				     struct mgcp_client_conf *conf);
 | 
									     struct mgcp_client_conf *conf);
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp);
 | 
				
			||||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports) OSMO_DEPRECATED("Use mgcp_client_connect() instead");
 | 
					int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
 | 
				
			||||||
void mgcp_client_disconnect(struct mgcp_client *mgcp);
 | 
					void mgcp_client_disconnect(struct mgcp_client *mgcp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
					const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ struct mgcp_client {
 | 
				
			|||||||
	mgcp_trans_id_t next_trans_id;
 | 
						mgcp_trans_id_t next_trans_id;
 | 
				
			||||||
	struct llist_head responses_pending;
 | 
						struct llist_head responses_pending;
 | 
				
			||||||
	struct llist_head inuse_endpoints;
 | 
						struct llist_head inuse_endpoints;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_inuse_endpoint {
 | 
					struct mgcp_inuse_endpoint {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,11 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client;
 | 
					struct mgcp_client;
 | 
				
			||||||
struct mgcp_client_pool;
 | 
					struct mgcp_client_pool;
 | 
				
			||||||
struct mgcp_client_pool_member;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
 | 
					struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx);
 | 
				
			||||||
 | 
					 | 
				
			||||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool);
 | 
				
			||||||
int mgcp_client_pool_config_write(struct vty *vty, const char *indent);
 | 
					 | 
				
			||||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
					unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
					struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
 | 
				
			||||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
 | 
				
			||||||
 | 
					 | 
				
			||||||
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr);
 | 
					 | 
				
			||||||
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member);
 | 
					 | 
				
			||||||
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member);
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,31 +1,9 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Struct to handle a pool of MGWs. (Use _pool functions) */
 | 
					 | 
				
			||||||
struct mgcp_client_pool {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
 | 
					 | 
				
			||||||
	 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
 | 
					 | 
				
			||||||
	struct mgcp_client *mgcp_client_single;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* A list that manages the pool members (see mgcp_client_pool_member->list above) */
 | 
					 | 
				
			||||||
	struct llist_head member_list;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
 | 
					 | 
				
			||||||
	 * mgcp_client_pool_vty_init() */
 | 
					 | 
				
			||||||
	char *vty_indent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
 | 
					 | 
				
			||||||
	struct cmd_node *vty_node;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Struct to handle a member of a pool of MGWs. */
 | 
					/* Struct to handle a member of a pool of MGWs. */
 | 
				
			||||||
struct mgcp_client_pool_member {
 | 
					struct mgcp_client_pool_member {
 | 
				
			||||||
	/* Entry in llist mgcp_client_pool->pool. */
 | 
					 | 
				
			||||||
	struct llist_head list;
 | 
						struct llist_head list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The pool managing this object: */
 | 
					 | 
				
			||||||
	struct mgcp_client_pool *pool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
 | 
						/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
 | 
				
			||||||
	 * the log. */
 | 
						 * the log. */
 | 
				
			||||||
	unsigned int nr;
 | 
						unsigned int nr;
 | 
				
			||||||
@@ -46,7 +24,22 @@ struct mgcp_client_pool_member {
 | 
				
			|||||||
	unsigned int refcount;
 | 
						unsigned int refcount;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr);
 | 
					/* Struct to handle a pool of MGWs. (Use _pool functions) */
 | 
				
			||||||
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member);
 | 
					struct mgcp_client_pool {
 | 
				
			||||||
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member);
 | 
					
 | 
				
			||||||
 | 
						/* A pointer to a 'single' mgcp client. This is a non-pooled MGCP client that is configured using
 | 
				
			||||||
 | 
						 * mgcp_client_vty_init() and actively registered by the API user using mgcp_client_pool_register_single() */
 | 
				
			||||||
 | 
						struct mgcp_client *mgcp_client_single;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A list that manages the pool members (see above) */
 | 
				
			||||||
 | 
						struct llist_head pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* String to use for indentation when writing the configuration file to the VTY. This field is populated by
 | 
				
			||||||
 | 
						 * mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						char *vty_indent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* VTY node specification used with this pool. This field is populated by mgcp_client_pool_vty_init() */
 | 
				
			||||||
 | 
						struct cmd_node *vty_node;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										74
									
								
								m4/ax_check_compile_flag.m4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								m4/ax_check_compile_flag.m4
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					# ===========================================================================
 | 
				
			||||||
 | 
					#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
 | 
				
			||||||
 | 
					# ===========================================================================
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SYNOPSIS
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# DESCRIPTION
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   Check whether the given FLAG works with the current language's compiler
 | 
				
			||||||
 | 
					#   or gives an error.  (Warnings, however, are ignored)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
 | 
				
			||||||
 | 
					#   success/failure.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   If EXTRA-FLAGS is defined, it is added to the current language's default
 | 
				
			||||||
 | 
					#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
 | 
				
			||||||
 | 
					#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
 | 
				
			||||||
 | 
					#   force the compiler to issue an error when a bad flag is given.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
 | 
				
			||||||
 | 
					#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# LICENSE
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
 | 
				
			||||||
 | 
					#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   This program is free software: you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					#   under the terms of the GNU 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 General
 | 
				
			||||||
 | 
					#   Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   You should have received a copy of the GNU General Public License along
 | 
				
			||||||
 | 
					#   with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   As a special exception, the respective Autoconf Macro's copyright owner
 | 
				
			||||||
 | 
					#   gives unlimited permission to copy, distribute and modify the configure
 | 
				
			||||||
 | 
					#   scripts that are the output of Autoconf when processing the Macro. You
 | 
				
			||||||
 | 
					#   need not follow the terms of the GNU General Public License when using
 | 
				
			||||||
 | 
					#   or distributing such scripts, even though portions of the text of the
 | 
				
			||||||
 | 
					#   Macro appear in them. The GNU General Public License (GPL) does govern
 | 
				
			||||||
 | 
					#   all other use of the material that constitutes the Autoconf Macro.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   This special exception to the GPL applies to versions of the Autoconf
 | 
				
			||||||
 | 
					#   Macro released by the Autoconf Archive. When you make and distribute a
 | 
				
			||||||
 | 
					#   modified version of the Autoconf Macro, you may extend this special
 | 
				
			||||||
 | 
					#   exception to the GPL to apply to your modified version as well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#serial 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AC_DEFUN([AX_CHECK_COMPILE_FLAG],
 | 
				
			||||||
 | 
					[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
 | 
				
			||||||
 | 
					AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
 | 
				
			||||||
 | 
					AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
 | 
				
			||||||
 | 
					  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
 | 
				
			||||||
 | 
					  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
 | 
				
			||||||
 | 
					  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
 | 
				
			||||||
 | 
					    [AS_VAR_SET(CACHEVAR,[yes])],
 | 
				
			||||||
 | 
					    [AS_VAR_SET(CACHEVAR,[no])])
 | 
				
			||||||
 | 
					  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
 | 
				
			||||||
 | 
					AS_VAR_IF(CACHEVAR,yes,
 | 
				
			||||||
 | 
					  [m4_default([$2], :)],
 | 
				
			||||||
 | 
					  [m4_default([$3], :)])
 | 
				
			||||||
 | 
					AS_VAR_POPDEF([CACHEVAR])dnl
 | 
				
			||||||
 | 
					])dnl AX_CHECK_COMPILE_FLAGS
 | 
				
			||||||
@@ -21,7 +21,7 @@ AM_LDFLAGS = \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# This is not at all related to the release version, but a range of supported
 | 
					# This is not at all related to the release version, but a range of supported
 | 
				
			||||||
# API versions. Read TODO_RELEASE in the source tree's root!
 | 
					# API versions. Read TODO_RELEASE in the source tree's root!
 | 
				
			||||||
MGCP_CLIENT_LIBVERSION=10:0:1
 | 
					MGCP_CLIENT_LIBVERSION=8:0:0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = \
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
	libosmo-mgcp-client.la \
 | 
						libosmo-mgcp-client.la \
 | 
				
			||||||
@@ -35,8 +35,4 @@ libosmo_mgcp_client_la_SOURCES = \
 | 
				
			|||||||
	mgcp_client_pool.c \
 | 
						mgcp_client_pool.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libosmo_mgcp_client_la_LDFLAGS = \
 | 
					libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
 | 
				
			||||||
	$(AM_LDFLAGS) \
 | 
					 | 
				
			||||||
	-version-info $(MGCP_CLIENT_LIBVERSION) \
 | 
					 | 
				
			||||||
	-no-undefined \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,6 @@ const struct value_string osmo_mgcpc_codec_names[] = {
 | 
				
			|||||||
	{ CODEC_GSMHR_8000_1, "GSM-HR-08/8000/1" },
 | 
						{ CODEC_GSMHR_8000_1, "GSM-HR-08/8000/1" },
 | 
				
			||||||
	{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
						{ CODEC_AMR_8000_1, "AMR/8000/1" },
 | 
				
			||||||
	{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
						{ CODEC_AMRWB_16000_1, "AMR-WB/16000/1" },
 | 
				
			||||||
	{ CODEC_IUFP, "VND.3GPP.IUFP/16000" },
 | 
					 | 
				
			||||||
	{ 0, NULL },
 | 
						{ 0, NULL },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -442,7 +441,7 @@ static int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "MGW offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return osmux_cid;
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -726,6 +725,10 @@ static int mgcp_do_read(struct osmo_fd *fd)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		msgb_free(msg);
 | 
							msgb_free(msg);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
						} else if (ret > 4096 - 128) {
 | 
				
			||||||
 | 
							LOGPMGW(mgcp, LOGL_ERROR, "Too much data: %s: %d\n", osmo_sock_get_name2(fd->fd), ret);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg->l2h = msgb_put(msg, ret);
 | 
						msg->l2h = msgb_put(msg, ret);
 | 
				
			||||||
@@ -769,7 +772,7 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
 | 
						mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
 | 
				
			||||||
		MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
 | 
							MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
 | 
				
			||||||
	mgcp->actual.local_port = conf->local_port > 0 ? (uint16_t)conf->local_port :
 | 
						mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
 | 
				
			||||||
		MGCP_CLIENT_LOCAL_PORT_DEFAULT;
 | 
							MGCP_CLIENT_LOCAL_PORT_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
 | 
						mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
 | 
				
			||||||
@@ -799,6 +802,49 @@ struct mgcp_client *mgcp_client_init(void *ctx,
 | 
				
			|||||||
	return mgcp;
 | 
						return mgcp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int init_socket(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wq = &mgcp->wq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < retry_n_ports + 1; i++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Initialize socket with the currently configured port number */
 | 
				
			||||||
 | 
							rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
				
			||||||
 | 
										 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
				
			||||||
 | 
										 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
				
			||||||
 | 
							if (rc > 0)
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* If there is a different port than the default port configured then we assume that the user has
 | 
				
			||||||
 | 
							 * chosen that port conciously and we will not try to resolve this by silently choosing a different
 | 
				
			||||||
 | 
							 * port. */
 | 
				
			||||||
 | 
							if (mgcp->actual.local_port != MGCP_CLIENT_LOCAL_PORT_DEFAULT && i == 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (i == retry_n_ports) {
 | 
				
			||||||
 | 
								/* Last try failed */
 | 
				
			||||||
 | 
								LOGPMGW(mgcp, LOGL_NOTICE, "Failed to bind to %s:%d -- check configuration!\n",
 | 
				
			||||||
 | 
								     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port);
 | 
				
			||||||
 | 
								if (retry_n_ports == 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								/* Choose a new port number to try next */
 | 
				
			||||||
 | 
								LOGPMGW(mgcp, LOGL_NOTICE,
 | 
				
			||||||
 | 
								     "Failed to bind to %s:%d, retrying with port %d -- check configuration!\n",
 | 
				
			||||||
 | 
								     mgcp->actual.local_addr ? mgcp->actual.local_addr : "(any)", mgcp->actual.local_port,
 | 
				
			||||||
 | 
								     mgcp->actual.local_port + 1);
 | 
				
			||||||
 | 
								mgcp->actual.local_port++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGPMGW(mgcp, LOGL_FATAL, "Failed to find a port to bind on %u times -- check configuration!\n", i);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
					/* Safely ignore the MGCP response to the DLCX sent via _mgcp_client_send_dlcx() */
 | 
				
			||||||
static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
					static void _ignore_mgcp_response(struct mgcp_response *response, void *priv) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -835,8 +881,9 @@ static const char *_mgcp_client_name_append_domain(const struct mgcp_client *mgc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! Initialize client connection (opens socket)
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 | 
					 *  \param[in] retry_n_ports number of consecutive local ports that should be used to retry on failure.
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
					int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_wqueue *wq;
 | 
						struct osmo_wqueue *wq;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -855,9 +902,7 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
						osmo_fd_setup(&wq->bfd, -1, OSMO_FD_READ, osmo_wqueue_bfd_cb, mgcp, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = osmo_sock_init2_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, mgcp->actual.local_addr,
 | 
						rc = init_socket(mgcp, retry_n_ports);
 | 
				
			||||||
				 mgcp->actual.local_port, mgcp->actual.remote_addr, mgcp->actual.remote_port,
 | 
					 | 
				
			||||||
				 OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
 | 
					 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPMGW(mgcp, LOGL_FATAL,
 | 
							LOGPMGW(mgcp, LOGL_FATAL,
 | 
				
			||||||
		     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
							     "Failed to initialize socket %s:%u -> %s:%u for MGW: %s\n",
 | 
				
			||||||
@@ -883,12 +928,12 @@ error_close_fd:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! DEPRECATED: Initialize client connection (opens socket)
 | 
					/*! Initialize client connection (opens socket)
 | 
				
			||||||
 *  \param[in,out] mgcp MGCP client descriptor.
 | 
					 *  \param[in,out] mgcp MGCP client descriptor.
 | 
				
			||||||
 *  \returns 0 on success, -EINVAL on error. */
 | 
					 *  \returns 0 on success, -EINVAL on error. */
 | 
				
			||||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports)
 | 
					int mgcp_client_connect(struct mgcp_client *mgcp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return mgcp_client_connect(mgcp);
 | 
						return mgcp_client_connect2(mgcp, 99);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Terminate client connection
 | 
					/*! Terminate client connection
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -227,7 +227,7 @@ static struct value_string osmo_mgcpc_ep_fsm_event_names[33] = {};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
					static char osmo_mgcpc_ep_fsm_event_name_bufs[32][32] = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fill_event_names(void)
 | 
					static void fill_event_names()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
						for (i = 0; i < (ARRAY_SIZE(osmo_mgcpc_ep_fsm_event_names) - 1); i++) {
 | 
				
			||||||
@@ -243,7 +243,7 @@ static void fill_event_names(void)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init(void)
 | 
					static __attribute__((constructor)) void osmo_mgcpc_ep_fsm_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&osmo_mgcpc_ep_fsm) == 0);
 | 
				
			||||||
	fill_event_names();
 | 
						fill_event_names();
 | 
				
			||||||
@@ -997,7 +997,7 @@ static int osmo_mgcpc_ep_fsm_timer_cb(struct osmo_fsm_inst *fi)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
 | 
					void osmo_mgcpc_ep_fsm_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
						struct osmo_mgcpc_ep *ep = osmo_mgcpc_ep_fi_mgwep(fi);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -760,7 +760,7 @@ const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
 | 
				
			|||||||
	return buf;
 | 
						return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init(void)
 | 
					static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
						OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm-generic/errno.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
@@ -28,6 +27,32 @@
 | 
				
			|||||||
#define LOGPPMGW(pool_member, level, fmt, args...) \
 | 
					#define LOGPPMGW(pool_member, level, fmt, args...) \
 | 
				
			||||||
LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
 | 
					LOGP(DLMGCP, level, "MGW-pool(%s) " fmt, mgcp_client_pool_member_name(pool_member), ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get a human readable name for a given pool member. */
 | 
				
			||||||
 | 
					const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct mgcp_client *mpcp_client;
 | 
				
			||||||
 | 
						struct mgcp_client mpcp_client_dummy;
 | 
				
			||||||
 | 
						static char name[512];
 | 
				
			||||||
 | 
						const char *description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pool_member)
 | 
				
			||||||
 | 
							return "(null)";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
 | 
				
			||||||
 | 
						 * initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
 | 
				
			||||||
 | 
							mpcp_client = &mpcp_client_dummy;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							mpcp_client = pool_member->client;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						description = mgcp_client_name(mpcp_client);
 | 
				
			||||||
 | 
						snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
 | 
					/*! Allocate MGCP client pool. This is called once on startup and before the pool is used with
 | 
				
			||||||
 *  mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
 | 
					 *  mgcp_client_pool_vty_init(). Since the pool is linked with the VTY it must exist througout the entire runtime.
 | 
				
			||||||
 *  \param[in] talloc_ctx talloc context. */
 | 
					 *  \param[in] talloc_ctx talloc context. */
 | 
				
			||||||
@@ -39,7 +64,7 @@ struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
 | 
				
			|||||||
	if (!pool)
 | 
						if (!pool)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_LLIST_HEAD(&pool->member_list);
 | 
						INIT_LLIST_HEAD(&pool->pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pool;
 | 
						return pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -52,10 +77,28 @@ unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
 | 
				
			|||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	unsigned int pool_members_initialized = 0;
 | 
						unsigned int pool_members_initialized = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Initialize client */
 | 
							/* Initialize client */
 | 
				
			||||||
		if (mgcp_client_pool_member_reinit_client(pool_member) == 0)
 | 
							pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
				
			||||||
 | 
							if (!pool_member->client) {
 | 
				
			||||||
 | 
								LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Set backpointer so that we can detect later that this MGCP client is managed
 | 
				
			||||||
 | 
							 * by this pool. */
 | 
				
			||||||
 | 
							pool_member->client->pool = pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Connect client */
 | 
				
			||||||
 | 
							if (mgcp_client_connect2(pool_member->client, 0)) {
 | 
				
			||||||
 | 
								LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
 | 
				
			||||||
 | 
									 pool_member->conf.remote_addr, pool_member->conf.remote_port);
 | 
				
			||||||
 | 
								talloc_free(pool_member->client);
 | 
				
			||||||
 | 
								pool_member->client = NULL;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pool_members_initialized++;
 | 
							pool_members_initialized++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,37 +118,23 @@ void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp
 | 
				
			|||||||
	pool->mgcp_client_single = mgcp_client;
 | 
						pool->mgcp_client_single = mgcp_client;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Lookup the selected MGCP client config by its reference number */
 | 
					 | 
				
			||||||
struct mgcp_client_pool_member *mgcp_client_pool_find_member_by_nr(struct mgcp_client_pool *pool, unsigned int nr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
					 | 
				
			||||||
		if (pool_member->nr == nr)
 | 
					 | 
				
			||||||
			return pool_member;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
					/* Not every pool member may have a functional MGCP client, we will run through the pool once until we meet a
 | 
				
			||||||
 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
					 * pool member that is suitable (has a client, is not blocked, has a low load). */
 | 
				
			||||||
static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
					static struct mgcp_client_pool_member *mgcp_client_pool_pick(struct mgcp_client_pool *pool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member_picked = NULL;
 | 
						struct mgcp_client_pool_member *pool_member_picked = NULL;
 | 
				
			||||||
	unsigned int n_pool_members = 0;
 | 
						unsigned int n_pool_members = llist_count(&pool->pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
		n_pool_members++;
 | 
					 | 
				
			||||||
		if (pool_member->blocked == false && pool_member->client) {
 | 
							if (pool_member->blocked == false && pool_member->client) {
 | 
				
			||||||
			if (!pool_member_picked)
 | 
								if (!pool_member_picked)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
			else if (pool_member_picked->refcount > pool_member->refcount)
 | 
								else if (pool_member_picked->refcount > pool_member->refcount)
 | 
				
			||||||
				pool_member_picked = pool_member;
 | 
									pool_member_picked = pool_member;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			LOGPPMGW(pool_member, LOGL_DEBUG, "%s -- MGW %u is unusable (blocked=%u, cli=%u)\n",
 | 
								LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
 | 
				
			||||||
				 __func__, pool_member->nr, pool_member->blocked, !!pool_member->client);
 | 
									 pool_member->nr);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -134,24 +163,26 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
 | 
				
			|||||||
	 *  by the application code. */
 | 
						 *  by the application code. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* When the pool is empty, return a single MGCP client if it is registered. */
 | 
						/* When the pool is empty, return a single MGCP client if it is registered. */
 | 
				
			||||||
	if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
 | 
						if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
 | 
							LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
 | 
				
			||||||
		     mgcp_client_name(pool->mgcp_client_single));
 | 
							     mgcp_client_name(pool->mgcp_client_single));
 | 
				
			||||||
		return pool->mgcp_client_single;
 | 
							return pool->mgcp_client_single;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Abort when the pool is empty */
 | 
						/* Abort when the pool is empty */
 | 
				
			||||||
	if (llist_empty(&pool->member_list)) {
 | 
						if (llist_empty(&pool->pool)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Pick a suitable pool member */
 | 
						/* Pick a suitable pool member */
 | 
				
			||||||
	pool_member = mgcp_client_pool_pick(pool);
 | 
						pool_member = mgcp_client_pool_pick(pool);
 | 
				
			||||||
	if (!pool_member)
 | 
						if (pool_member) {
 | 
				
			||||||
		return NULL;
 | 
							pool_member->refcount++;
 | 
				
			||||||
 | 
							return pool_member->client;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return mgcp_client_pool_member_get(pool_member);
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! put an MGCP client back into the pool (decrement reference counter).
 | 
					/*! put an MGCP client back into the pool (decrement reference counter).
 | 
				
			||||||
@@ -163,130 +194,23 @@ struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
 | 
				
			|||||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
 | 
					void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
						struct mgcp_client_pool *pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mgcp_client)
 | 
						if (!mgcp_client)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mgcp_client->pool_member)
 | 
						if (mgcp_client->pool)
 | 
				
			||||||
 | 
							pool = mgcp_client->pool;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	pool_member = mgcp_client->pool_member;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
							if (pool_member->client == mgcp_client) {
 | 
				
			||||||
			if (pool_member->refcount == 0) {
 | 
								if (pool_member->refcount == 0) {
 | 
				
			||||||
				LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
									LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pool_member->refcount--;
 | 
								pool_member->refcount--;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/***************************
 | 
					 | 
				
			||||||
 * mgcp_client_pool_member:
 | 
					 | 
				
			||||||
 ***************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Allocate an mgcp_client_pool_member.
 | 
					 | 
				
			||||||
 *  \param[in] pool MGCP client pool descriptor.
 | 
					 | 
				
			||||||
 *  \param[in] nr Reference number of the pool member.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct mgcp_client_pool_member *mgcp_client_pool_member_alloc(struct mgcp_client_pool *pool, unsigned int nr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pool_member = talloc_zero(pool, struct mgcp_client_pool_member);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(pool_member);
 | 
					 | 
				
			||||||
	mgcp_client_conf_init(&pool_member->conf);
 | 
					 | 
				
			||||||
	pool_member->pool = pool;
 | 
					 | 
				
			||||||
	pool_member->nr = nr;
 | 
					 | 
				
			||||||
	llist_add_tail(&pool_member->list, &pool->member_list);
 | 
					 | 
				
			||||||
	return pool_member;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Free an mgcp_client_pool_member allocated through mgcp_client_pool_member_alloc().
 | 
					 | 
				
			||||||
 *  \param[in] pool_member MGCP client pool descriptor.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * It also frees the associated MGCP client if present.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void mgcp_client_pool_member_free(struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	llist_del(&pool_member->list);
 | 
					 | 
				
			||||||
	if (pool_member->client) {
 | 
					 | 
				
			||||||
		mgcp_client_disconnect(pool_member->client);
 | 
					 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	talloc_free(pool_member);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Recreate and reconnect the MGCP client associated to the pool descriptor.
 | 
					 | 
				
			||||||
 *  \param[in] pool_member MGCP client pool descriptor.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
int mgcp_client_pool_member_reinit_client(struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* Get rid of a possibly existing old MGCP client instance first */
 | 
					 | 
				
			||||||
	if (pool_member->client) {
 | 
					 | 
				
			||||||
		mgcp_client_disconnect(pool_member->client);
 | 
					 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Initialize client */
 | 
					 | 
				
			||||||
	pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
					 | 
				
			||||||
	if (!pool_member->client) {
 | 
					 | 
				
			||||||
		LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client initialization failed\n");
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
					 | 
				
			||||||
	pool_member->client->pool_member = pool_member;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Connect client */
 | 
					 | 
				
			||||||
	if (mgcp_client_connect(pool_member->client)) {
 | 
					 | 
				
			||||||
		LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
 | 
					 | 
				
			||||||
				pool_member->conf.remote_addr, pool_member->conf.remote_port);
 | 
					 | 
				
			||||||
		talloc_free(pool_member->client);
 | 
					 | 
				
			||||||
		pool_member->client = NULL;
 | 
					 | 
				
			||||||
		return -ECONNABORTED;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Get a human readable name for a given pool member. */
 | 
					 | 
				
			||||||
const char *mgcp_client_pool_member_name(const struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const struct mgcp_client *mpcp_client;
 | 
					 | 
				
			||||||
	struct mgcp_client mpcp_client_dummy;
 | 
					 | 
				
			||||||
	static char name[512];
 | 
					 | 
				
			||||||
	const char *description;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pool_member)
 | 
					 | 
				
			||||||
		return "(null)";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* It is not guranteed that a pool_member has an MGCP client. The client may not yet be initialized or the
 | 
					 | 
				
			||||||
	 * initalization may have been failed. In this case we will generate a dummy MGCP client to work with. */
 | 
					 | 
				
			||||||
	if (!pool_member->client) {
 | 
					 | 
				
			||||||
		memcpy(&mpcp_client_dummy.actual, &pool_member->conf, sizeof(mpcp_client_dummy.actual));
 | 
					 | 
				
			||||||
		mpcp_client = &mpcp_client_dummy;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		mpcp_client = pool_member->client;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	description = mgcp_client_name(mpcp_client);
 | 
					 | 
				
			||||||
	snprintf(name, sizeof(name), "%d:%s", pool_member->nr, description);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return name;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Get the MGCP client associated with the pool reference from the pool (increment reference counter).
 | 
					 | 
				
			||||||
 *  \param[in] pool_member MGCP client pool descriptor.
 | 
					 | 
				
			||||||
 *  \returns MGCP client descriptor, NULL if no member was not ready.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct mgcp_client *mgcp_client_pool_member_get(struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	pool_member->refcount++;
 | 
					 | 
				
			||||||
	return pool_member->client;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Get whether the MGCP client associated with the pool reference is blocked by policy.
 | 
					 | 
				
			||||||
 *  \param[in] pool_member MGCP client pool descriptor.
 | 
					 | 
				
			||||||
 *  \returns true if blocked, false otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool mgcp_client_pool_member_is_blocked(const struct mgcp_client_pool_member *pool_member)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return pool_member->blocked;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,11 +32,10 @@
 | 
				
			|||||||
#include <osmocom/mgcp_client/mgcp_client.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_internal.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
					#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
 | 
				
			||||||
#include <osmocom/mgcp_client/mgcp_client_pool.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
					#define MGW_STR MGCP_CLIENT_MGW_STR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Only common (non-pooled) VTY commands will use this talloc context. All
 | 
					/* Only common (non-pooled) VTY connands will use this talloc context. All
 | 
				
			||||||
 * pooled VTY commands will use the pool (global_mgcp_client_pool) as
 | 
					 * pooled VTY commands will use the pool (global_mgcp_client_pool) as
 | 
				
			||||||
 * talloc context. */
 | 
					 * talloc context. */
 | 
				
			||||||
static void *global_mgcp_client_ctx = NULL;
 | 
					static void *global_mgcp_client_ctx = NULL;
 | 
				
			||||||
@@ -52,18 +51,13 @@ struct mgcp_client_conf *get_mgcp_client_config(struct vty *vty)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
						if (global_mgcp_client_pool && vty->node == global_mgcp_client_pool->vty_node->node)
 | 
				
			||||||
		return vty->index;
 | 
							return vty->index;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
	/* Global single MGCP config, deprecated: */
 | 
					 | 
				
			||||||
	vty_out(vty, "%% MGCP commands outside of 'mgw' nodes are deprecated. "
 | 
					 | 
				
			||||||
		"You should consider reading User Manual and migrating to 'mgw' node.%s",
 | 
					 | 
				
			||||||
		VTY_NEWLINE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return global_mgcp_client_conf;
 | 
							return global_mgcp_client_conf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
					DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
 | 
				
			||||||
      "local-ip " VTY_IPV46_CMD,
 | 
					      "mgw local-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      "local bind to connect to MGW from\n"
 | 
					      MGW_STR "local bind to connect to MGW from\n"
 | 
				
			||||||
      "local bind IPv4 address\n"
 | 
					      "local bind IPv4 address\n"
 | 
				
			||||||
      "local bind IPv6 address\n")
 | 
					      "local bind IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -78,16 +72,10 @@ ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
 | 
				
			|||||||
		 "mgcpgw local-ip A.B.C.D",
 | 
							 "mgcpgw local-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind IP address\n")
 | 
							 "local bind IP address\n")
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_local_ip,
 | 
					 | 
				
			||||||
		 cfg_mgw_mgw_local_ip_cmd,
 | 
					 | 
				
			||||||
		 "mgw local-ip " VTY_IPV46_CMD,
 | 
					 | 
				
			||||||
		 MGW_STR "local bind to connect to MGW from\n"
 | 
					 | 
				
			||||||
		 "local bind IPv4 address\n"
 | 
					 | 
				
			||||||
		 "local bind IPv6 address\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
					DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
 | 
				
			||||||
      "local-port <0-65535>",
 | 
					      "mgw local-port <0-65535>",
 | 
				
			||||||
      "local port to connect to MGW from\n"
 | 
					      MGW_STR "local port to connect to MGW from\n"
 | 
				
			||||||
      "local bind port\n")
 | 
					      "local bind port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -99,15 +87,10 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
 | 
				
			|||||||
		 "mgcpgw local-port <0-65535>",
 | 
							 "mgcpgw local-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "local bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "local bind port\n")
 | 
							 "local bind port\n")
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_local_port,
 | 
					 | 
				
			||||||
		 cfg_mgw_mgw_local_port_cmd,
 | 
					 | 
				
			||||||
		 "mgw local-port <0-65535>",
 | 
					 | 
				
			||||||
		 MGW_STR "local port to connect to MGW from\n"
 | 
					 | 
				
			||||||
		 "local bind port\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
					DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
 | 
				
			||||||
      "remote-ip " VTY_IPV46_CMD,
 | 
					      "mgw remote-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      "remote IP address to reach the MGW at\n"
 | 
					      MGW_STR "remote IP address to reach the MGW at\n"
 | 
				
			||||||
      "remote IPv4 address\n"
 | 
					      "remote IPv4 address\n"
 | 
				
			||||||
      "remote IPv6 address\n")
 | 
					      "remote IPv6 address\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -121,16 +104,10 @@ ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
 | 
				
			|||||||
		 "mgcpgw remote-ip A.B.C.D",
 | 
							 "mgcpgw remote-ip A.B.C.D",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind IP address\n")
 | 
							 "remote bind IP address\n")
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_remote_ip,
 | 
					 | 
				
			||||||
		 cfg_mgw_mgw_remote_ip_cmd,
 | 
					 | 
				
			||||||
		 "mgw remote-ip " VTY_IPV46_CMD,
 | 
					 | 
				
			||||||
		 MGW_STR "remote IP address to reach the MGW at\n"
 | 
					 | 
				
			||||||
		 "remote IPv4 address\n"
 | 
					 | 
				
			||||||
		 "remote IPv6 address\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
					DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
 | 
				
			||||||
      "remote-port <0-65535>",
 | 
					      "mgw remote-port <0-65535>",
 | 
				
			||||||
      "remote port to reach the MGW at\n"
 | 
					      MGW_STR "remote port to reach the MGW at\n"
 | 
				
			||||||
      "remote port\n")
 | 
					      "remote port\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -142,13 +119,8 @@ ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
 | 
				
			|||||||
		 "mgcpgw remote-port <0-65535>",
 | 
							 "mgcpgw remote-port <0-65535>",
 | 
				
			||||||
		 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
							 MGW_STR "remote bind to connect to MGCP gateway with\n"
 | 
				
			||||||
		 "remote bind port\n")
 | 
							 "remote bind port\n")
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_remote_port,
 | 
					 | 
				
			||||||
		 cfg_mgw_mgw_remote_port_cmd,
 | 
					 | 
				
			||||||
		 "mgw remote-port <0-65535>",
 | 
					 | 
				
			||||||
		 MGW_STR "remote port to reach the MGW at\n"
 | 
					 | 
				
			||||||
		 "remote port\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
 | 
					DEFUN_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
					      MGW_STR "DEPRECATED: the endpoint range cannot be defined by the client\n"
 | 
				
			||||||
      "-\n" "-\n")
 | 
					      "-\n" "-\n")
 | 
				
			||||||
@@ -158,7 +130,7 @@ DEFUN_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgw_mgw_endpoint_range_cmd,
 | 
				
			|||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
					ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
 | 
				
			||||||
      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
					      "mgcpgw endpoint-range <1-65534> <1-65534>",
 | 
				
			||||||
      MGW_STR "usable range of endpoint identifiers\n"
 | 
					      MGW_STR "usable range of endpoint identifiers\n"
 | 
				
			||||||
      "set first useable endpoint identifier\n"
 | 
					      "set first useable endpoint identifier\n"
 | 
				
			||||||
@@ -186,8 +158,8 @@ ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_endpoint_domain_name,
 | 
					DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			||||||
      cfg_mgw_endpoint_domain_name_cmd,
 | 
					      cfg_mgw_endpoint_domain_name_cmd,
 | 
				
			||||||
      "endpoint-domain NAME",
 | 
					      "mgw endpoint-domain NAME",
 | 
				
			||||||
      "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
					      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
				
			||||||
      "Domain name, should be alphanumeric.\n")
 | 
					      "Domain name, should be alphanumeric.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
						struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
 | 
				
			||||||
@@ -200,16 +172,11 @@ DEFUN(cfg_mgw_endpoint_domain_name,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_endpoint_domain_name,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_endpoint_domain_name_cmd,
 | 
					 | 
				
			||||||
      "mgw endpoint-domain NAME",
 | 
					 | 
				
			||||||
      MGW_STR "Set the domain name to send in MGCP messages, e.g. the part 'foo' in 'rtpbridge/*@foo'.\n"
 | 
					 | 
				
			||||||
      "Domain name, should be alphanumeric.\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_reset_ep_name,
 | 
					DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			||||||
      cfg_mgw_reset_ep_name_cmd,
 | 
					      cfg_mgw_reset_ep_name_cmd,
 | 
				
			||||||
      "reset-endpoint NAME",
 | 
					      "mgw reset-endpoint NAME",
 | 
				
			||||||
      "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
					      MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
				
			||||||
      "e.g. 'rtpbridge/*'\n"
 | 
					      "e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -247,17 +214,11 @@ DEFUN(cfg_mgw_reset_ep_name,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_reset_ep_name,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_reset_ep_name_cmd,
 | 
					 | 
				
			||||||
      "mgw reset-endpoint NAME",
 | 
					 | 
				
			||||||
      MGW_STR "Add an endpoint name that should be reset (DLCX) on connect to the reset-endpoint list,"
 | 
					 | 
				
			||||||
      "e.g. 'rtpbridge/*'\n"
 | 
					 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgw_no_reset_ep_name,
 | 
					DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			||||||
      cfg_mgw_no_reset_ep_name_cmd,
 | 
					      cfg_mgw_no_reset_ep_name_cmd,
 | 
				
			||||||
      "no reset-endpoint NAME",
 | 
					      "no mgw reset-endpoint NAME",
 | 
				
			||||||
      NO_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
					      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct reset_ep *reset_ep;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
@@ -274,11 +235,6 @@ DEFUN(cfg_mgw_no_reset_ep_name,
 | 
				
			|||||||
	vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
						vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
	return CMD_WARNING;
 | 
						return CMD_WARNING;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
ALIAS_DEPRECATED(cfg_mgw_no_reset_ep_name,
 | 
					 | 
				
			||||||
      cfg_mgw_mgw_no_reset_ep_name_cmd,
 | 
					 | 
				
			||||||
      "no mgw reset-endpoint NAME",
 | 
					 | 
				
			||||||
      NO_STR MGW_STR "remove an endpoint name from the reset-endpoint list, e.g. 'rtpbridge/*'\n"
 | 
					 | 
				
			||||||
      "Endpoint name, e.g. 'rtpbridge/*' or 'ds/e1-0/s-3/su16-4'.\n")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
					static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -286,36 +242,33 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
 | 
				
			|||||||
	int port;
 | 
						int port;
 | 
				
			||||||
	struct reset_ep *reset_ep;
 | 
						struct reset_ep *reset_ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If caller doesn't the MGW pool API (mgcp_client_pool_vty_init was never called),
 | 
						if (conf->description)
 | 
				
			||||||
	 * then the "mgw" cmd prefix must be added since the old node always contained it.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	const char *mgw_prefix = global_mgcp_client_pool ? "" : "mgw ";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conf->description) /* description never had "mgw" prefix even on old node: */
 | 
					 | 
				
			||||||
		vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
							vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = conf->local_addr;
 | 
						addr = conf->local_addr;
 | 
				
			||||||
	if (addr)
 | 
						if (addr)
 | 
				
			||||||
		vty_out(vty, "%s%slocal-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
							vty_out(vty, "%smgw local-ip %s%s", indent, addr,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	port = conf->local_port;
 | 
						port = conf->local_port;
 | 
				
			||||||
	if (port >= 0)
 | 
						if (port >= 0)
 | 
				
			||||||
		vty_out(vty, "%s%slocal-port %u%s", indent, mgw_prefix,
 | 
							vty_out(vty, "%smgw local-port %u%s", indent,
 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = conf->remote_addr;
 | 
						addr = conf->remote_addr;
 | 
				
			||||||
	if (addr)
 | 
						if (addr)
 | 
				
			||||||
		vty_out(vty, "%s%sremote-ip %s%s", indent, mgw_prefix, addr, VTY_NEWLINE);
 | 
							vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
 | 
				
			||||||
 | 
								VTY_NEWLINE);
 | 
				
			||||||
	port = conf->remote_port;
 | 
						port = conf->remote_port;
 | 
				
			||||||
	if (port >= 0)
 | 
						if (port >= 0)
 | 
				
			||||||
		vty_out(vty, "%s%sremote-port %u%s", indent, mgw_prefix,
 | 
							vty_out(vty, "%smgw remote-port %u%s", indent,
 | 
				
			||||||
			(uint16_t)port, VTY_NEWLINE);
 | 
								(uint16_t)port, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conf->endpoint_domain_name[0])
 | 
						if (conf->endpoint_domain_name[0])
 | 
				
			||||||
		vty_out(vty, "%s%sendpoint-domain %s%s", indent, mgw_prefix,
 | 
							vty_out(vty, "%smgw endpoint-domain %s%s", indent,
 | 
				
			||||||
			conf->endpoint_domain_name, VTY_NEWLINE);
 | 
								conf->endpoint_domain_name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
						llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
 | 
				
			||||||
		vty_out(vty, "%s%sreset-endpoint %s%s", indent, mgw_prefix, reset_ep->name, VTY_NEWLINE);
 | 
							vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -326,11 +279,6 @@ static int config_write(struct vty *vty, const char *indent, struct mgcp_client_
 | 
				
			|||||||
 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
					 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
				
			||||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
					int mgcp_client_config_write(struct vty *vty, const char *indent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* If caller supports MGW pool API (mgcp_client_pool_vty_init was
 | 
					 | 
				
			||||||
	 * called), then skip printing any config in this node and print it when
 | 
					 | 
				
			||||||
	 * the whole 'mgw' node is printed. */
 | 
					 | 
				
			||||||
	if (global_mgcp_client_pool)
 | 
					 | 
				
			||||||
		return CMD_SUCCESS;
 | 
					 | 
				
			||||||
	return config_write(vty, indent, global_mgcp_client_conf);
 | 
						return config_write(vty, indent, global_mgcp_client_conf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -338,15 +286,15 @@ static void vty_init_common(void *talloc_ctx, int node)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	global_mgcp_client_ctx = talloc_ctx;
 | 
						global_mgcp_client_ctx = talloc_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* deprecated 'mgw' commands ('mgw' prepended as first arg) */
 | 
						install_lib_element(node, &cfg_mgw_local_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_local_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_local_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_local_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_remote_ip_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_remote_ip_cmd);
 | 
						install_lib_element(node, &cfg_mgw_remote_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_remote_port_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_endpoint_range_cmd);
 | 
						install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_endpoint_domain_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
 | 
				
			||||||
	install_lib_element(node, &cfg_mgw_mgw_no_reset_ep_name_cmd);
 | 
						install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	osmo_fsm_vty_add_cmds();
 | 
						osmo_fsm_vty_add_cmds();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -371,62 +319,38 @@ void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *c
 | 
				
			|||||||
	vty_init_common(talloc_ctx, node);
 | 
						vty_init_common(talloc_ctx, node);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Mark whether user called mgcp_client_pool_config_write() and hence support new API */
 | 
					static int config_write_pool(struct vty *vty)
 | 
				
			||||||
static bool mgcp_client_pool_config_write_called = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int _mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
						struct mgcp_client_pool *pool = global_mgcp_client_pool;
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
	unsigned int subindent_buf_len;
 | 
						unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
 | 
				
			||||||
	char *subindent;
 | 
						char *indent = talloc_zero_size(vty, indent_buf_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!indent)
 | 
						snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
 | 
				
			||||||
		indent = pool->vty_indent ? : "";
 | 
					 | 
				
			||||||
	subindent_buf_len = strlen(indent) + 1 + 1;
 | 
					 | 
				
			||||||
	subindent = talloc_zero_size(vty, subindent_buf_len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(subindent, subindent_buf_len, "%s ", indent);
 | 
						llist_for_each_entry(pool_member, &pool->pool, list) {
 | 
				
			||||||
 | 
							vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
 | 
				
			||||||
	llist_for_each_entry(pool_member, &pool->member_list, list) {
 | 
							config_write(vty, indent, &pool_member->conf);
 | 
				
			||||||
		vty_out(vty, "%smgw %u%s", indent, pool_member->nr, VTY_NEWLINE);
 | 
					 | 
				
			||||||
		config_write(vty, subindent, &pool_member->conf);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* MGW pool API is supported by user (global_mgcp_client_pool is set
 | 
						talloc_free(indent);
 | 
				
			||||||
	 * because mgcp_client_pool_vty_init was called). If single MGW was
 | 
					 | 
				
			||||||
	 * configured through old VTY and no mgw in the new MGW pool VTY is
 | 
					 | 
				
			||||||
	 * replacing it, then output the single MGW converted to the new MGW
 | 
					 | 
				
			||||||
	 * pool VTY. */
 | 
					 | 
				
			||||||
	if (llist_empty(&pool->member_list) && pool->mgcp_client_single) {
 | 
					 | 
				
			||||||
		vty_out(vty, "%smgw 0%s", indent, VTY_NEWLINE);
 | 
					 | 
				
			||||||
		config_write(vty, subindent, global_mgcp_client_conf);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	talloc_free(subindent);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Deprecated, used for backward compatibility with older users which didn't call
 | 
					/* Lookup the selected MGCP client config by its reference number */
 | 
				
			||||||
 * mgcp_client_pool_config_write(): */
 | 
					static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
 | 
				
			||||||
static int config_write_pool(struct vty *vty)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (mgcp_client_pool_config_write_called)
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
						struct mgcp_client_pool_member *pool_member_tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return _mgcp_client_pool_config_write(vty, NULL);
 | 
						llist_for_each_entry(pool_member_tmp, &global_mgcp_client_pool->pool, list) {
 | 
				
			||||||
}
 | 
							if (pool_member_tmp->nr == nr) {
 | 
				
			||||||
 | 
								pool_member = pool_member_tmp;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Write out MGCP client config to VTY.
 | 
						return pool_member;
 | 
				
			||||||
 *  \param[in] vty VTY to which we should print.
 | 
					 | 
				
			||||||
 *  \param[in] indent string used for indentation (e.g. " ").
 | 
					 | 
				
			||||||
	       If NULL, indentation passed during mgcp_client_pool_vty_init() will be used.
 | 
					 | 
				
			||||||
 *  \returns CMD_SUCCESS on success, CMD_WARNING on error */
 | 
					 | 
				
			||||||
int mgcp_client_pool_config_write(struct vty *vty, const char *indent)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* Tell internal node write function that the user supports calling proper API: */
 | 
					 | 
				
			||||||
	mgcp_client_pool_config_write_called = true;
 | 
					 | 
				
			||||||
	return _mgcp_client_pool_config_write(vty, indent);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN_ATTR(cfg_mgw,
 | 
					DEFUN_ATTR(cfg_mgw,
 | 
				
			||||||
@@ -435,10 +359,13 @@ DEFUN_ATTR(cfg_mgw,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		pool_member = mgcp_client_pool_member_alloc(global_mgcp_client_pool, nr);
 | 
							pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_pool_member);
 | 
				
			||||||
		OSMO_ASSERT(pool_member);
 | 
							OSMO_ASSERT(pool_member);
 | 
				
			||||||
 | 
							mgcp_client_conf_init(&pool_member->conf);
 | 
				
			||||||
 | 
							pool_member->nr = nr;
 | 
				
			||||||
 | 
							llist_add_tail(&pool_member->list, &global_mgcp_client_pool->pool);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty->index = &pool_member->conf;
 | 
						vty->index = &pool_member->conf;
 | 
				
			||||||
@@ -455,7 +382,7 @@ DEFUN_ATTR(cfg_no_mgw,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -468,7 +395,12 @@ DEFUN_ATTR(cfg_no_mgw,
 | 
				
			|||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_client_pool_member_free(pool_member);
 | 
						llist_del(&pool_member->list);
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						talloc_free(pool_member);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -480,7 +412,7 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -493,10 +425,32 @@ DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
 | 
				
			|||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_client_pool_member_reinit_client(pool_member) < 0) {
 | 
						/* Get rid of a possibly existing old MGCP client instance first */
 | 
				
			||||||
 | 
						if (pool_member->client) {
 | 
				
			||||||
 | 
							mgcp_client_disconnect(pool_member->client);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Create a new MGCP client instance with the current config */
 | 
				
			||||||
 | 
						pool_member->client = mgcp_client_init(pool_member, &pool_member->conf);
 | 
				
			||||||
 | 
						if (!pool_member->client) {
 | 
				
			||||||
 | 
							LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s initalization failed\n",
 | 
				
			||||||
 | 
							     mgcp_client_pool_member_name(pool_member));
 | 
				
			||||||
 | 
							vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
				
			||||||
 | 
								mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set backpointer so that we can detect later that this MGCP client is managed by this pool. */
 | 
				
			||||||
 | 
						pool_member->client->pool = global_mgcp_client_pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Connect client */
 | 
				
			||||||
 | 
						if (mgcp_client_connect(pool_member->client)) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
 | 
							LOGP(DLMGCP, LOGL_ERROR, "(manual) MGW %s connect failed at (%s:%u)\n",
 | 
				
			||||||
		     mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
 | 
							     mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
 | 
				
			||||||
		     pool_member->conf.remote_port);
 | 
							     pool_member->conf.remote_port);
 | 
				
			||||||
 | 
							talloc_free(pool_member->client);
 | 
				
			||||||
 | 
							pool_member->client = NULL;
 | 
				
			||||||
		vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
							vty_out(vty, "%% MGCP client (MGW %s) initalization failed ('%s')%s",
 | 
				
			||||||
			mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
								mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -512,7 +466,7 @@ DEFUN_ATTR(mgw_block, mgw_block_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -529,7 +483,7 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
 | 
				
			|||||||
	int nr = atoi(argv[0]);
 | 
						int nr = atoi(argv[0]);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member = NULL;
 | 
						struct mgcp_client_pool_member *pool_member = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool_member = mgcp_client_pool_find_member_by_nr(global_mgcp_client_pool, nr);
 | 
						pool_member = pool_member_by_nr(nr);
 | 
				
			||||||
	if (!pool_member) {
 | 
						if (!pool_member) {
 | 
				
			||||||
		vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
							vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
@@ -539,20 +493,20 @@ DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
 | 
					DEFUN(mgw_show, mgw_snow_cmd, "show mgw-pool", SHOW_STR "Display information about the MGW-Pool\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
 | 
						vty_out(vty, "%% MGW-Pool:%s", VTY_NEWLINE);
 | 
				
			||||||
	struct mgcp_client_pool_member *pool_member;
 | 
						struct mgcp_client_pool_member *pool_member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (llist_empty(&global_mgcp_client_pool->member_list) && global_mgcp_client_pool->mgcp_client_single) {
 | 
						if (llist_empty(&global_mgcp_client_pool->pool) && global_mgcp_client_pool->mgcp_client_single) {
 | 
				
			||||||
		vty_out(vty, "%%  (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
 | 
							vty_out(vty, "%%  (pool is empty, single MGCP client will be used)%s", VTY_NEWLINE);
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	} else if (llist_empty(&global_mgcp_client_pool->member_list)) {
 | 
						} else if (llist_empty(&global_mgcp_client_pool->pool)) {
 | 
				
			||||||
		vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
							vty_out(vty, "%%  (pool is empty)%s", VTY_NEWLINE);
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	llist_for_each_entry(pool_member, &global_mgcp_client_pool->member_list, list) {
 | 
						llist_for_each_entry(pool_member, &global_mgcp_client_pool->pool, list) {
 | 
				
			||||||
		vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
							vty_out(vty, "%%  MGW %s%s", mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
							vty_out(vty, "%%   mgcp-client:   %s%s", pool_member->client ? "connected" : "disconnected",
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
@@ -566,8 +520,7 @@ DEFUN(mgw_show, mgw_show_cmd, "show mgw-pool", SHOW_STR "Display information abo
 | 
				
			|||||||
 *  (called once at startup by the application process).
 | 
					 *  (called once at startup by the application process).
 | 
				
			||||||
 *  \param[in] parent_node identifier of the parent node on which the mgw node appears.
 | 
					 *  \param[in] parent_node identifier of the parent node on which the mgw node appears.
 | 
				
			||||||
 *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.
 | 
					 *  \param[in] mgw_node identifier that should be used with the newly installed MGW node.
 | 
				
			||||||
 *  \param[in] indent indentation string to match the indentation in the VTY config.
 | 
					 *  \param[in] indent indentation string to match the indentation in the VTY config
 | 
				
			||||||
	       If NULL, it must be passed explicitly each time mgcp_client_pool_config_write() is called.
 | 
					 | 
				
			||||||
 *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
 | 
					 *  \param[in] pool user provided memory to store the configured MGCP client (MGW) pool. */
 | 
				
			||||||
void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
 | 
					void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent, struct mgcp_client_pool *pool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -575,12 +528,11 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	OSMO_ASSERT(pool);
 | 
						OSMO_ASSERT(pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Never allow this function to be called twice on the same pool */
 | 
						/* Never allow this function to be called twice on the same pool */
 | 
				
			||||||
 | 
						OSMO_ASSERT(!pool->vty_indent);
 | 
				
			||||||
	OSMO_ASSERT(!pool->vty_node);
 | 
						OSMO_ASSERT(!pool->vty_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (indent) {
 | 
					 | 
				
			||||||
	pool->vty_indent = talloc_strdup(pool, indent);
 | 
						pool->vty_indent = talloc_strdup(pool, indent);
 | 
				
			||||||
	OSMO_ASSERT(pool->vty_indent);
 | 
						OSMO_ASSERT(pool->vty_indent);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pool->vty_node = talloc_zero(pool, struct cmd_node);
 | 
						pool->vty_node = talloc_zero(pool, struct cmd_node);
 | 
				
			||||||
	OSMO_ASSERT(pool->vty_node);
 | 
						OSMO_ASSERT(pool->vty_node);
 | 
				
			||||||
	pool->vty_node->node = mgw_node;
 | 
						pool->vty_node->node = mgw_node;
 | 
				
			||||||
@@ -590,19 +542,8 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	install_lib_element(parent_node, &cfg_mgw_cmd);
 | 
						install_lib_element(parent_node, &cfg_mgw_cmd);
 | 
				
			||||||
	install_lib_element(parent_node, &cfg_no_mgw_cmd);
 | 
						install_lib_element(parent_node, &cfg_no_mgw_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: config_write_pool is deprecated and user is expected to
 | 
					 | 
				
			||||||
	 * manually call mgcp_client_pool_config_write() when printing the VTY
 | 
					 | 
				
			||||||
	 * config */
 | 
					 | 
				
			||||||
	install_node(pool->vty_node, config_write_pool);
 | 
						install_node(pool->vty_node, config_write_pool);
 | 
				
			||||||
	vty_init_common(pool, mgw_node);
 | 
						vty_init_common(pool, mgw_node);
 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_local_ip_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_local_port_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_remote_ip_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_remote_port_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_rtp_bts_base_port_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_endpoint_domain_name_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_reset_ep_name_cmd);
 | 
					 | 
				
			||||||
	install_lib_element(mgw_node, &cfg_mgw_no_reset_ep_name_cmd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_element(mgw_node, &cfg_description_cmd);
 | 
						install_element(mgw_node, &cfg_description_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -610,7 +551,7 @@ void mgcp_client_pool_vty_init(int parent_node, int mgw_node, const char *indent
 | 
				
			|||||||
	install_lib_element(ENABLE_NODE, &mgw_block_cmd);
 | 
						install_lib_element(ENABLE_NODE, &mgw_block_cmd);
 | 
				
			||||||
	install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
 | 
						install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	install_lib_element_ve(&mgw_show_cmd);
 | 
						install_lib_element_ve(&mgw_snow_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	global_mgcp_client_pool = pool;
 | 
						global_mgcp_client_pool = pool;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ libosmo_mgcp_a_SOURCES = \
 | 
				
			|||||||
	mgcp_stat.c \
 | 
						mgcp_stat.c \
 | 
				
			||||||
	mgcp_endp.c \
 | 
						mgcp_endp.c \
 | 
				
			||||||
	mgcp_trunk.c \
 | 
						mgcp_trunk.c \
 | 
				
			||||||
 | 
						mgcp_ctrl.c \
 | 
				
			||||||
	mgcp_ratectr.c \
 | 
						mgcp_ratectr.c \
 | 
				
			||||||
	mgcp_e1.c \
 | 
						mgcp_e1.c \
 | 
				
			||||||
	mgcp_iuup.c \
 | 
					 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,10 @@
 | 
				
			|||||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 *  GNU General Public License for more details.
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int val_seg(int val)
 | 
					static inline int val_seg(int val)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -345,18 +345,6 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */
 | 
					 | 
				
			||||||
bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (codec->param_present == false)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (!codec->param.amr_octet_aligned_present)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
					/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
 | 
				
			||||||
 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
					 * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
 | 
				
			||||||
 * Media Type Registration":
 | 
					 * Media Type Registration":
 | 
				
			||||||
@@ -367,7 +355,7 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec)
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * https://tools.ietf.org/html/rfc4867
 | 
					 * https://tools.ietf.org/html/rfc4867
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
					static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!codec->param_present)
 | 
						if (!codec->param_present)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -390,10 +378,10 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
 | 
				
			|||||||
		return false;
 | 
							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")) {
 | 
				
			||||||
	/* Note: AMR allows to set the RTP payload format to octet-aligned or bandwith-efficient (octet-aligned=0)
 | 
							if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
 | 
				
			||||||
	 * via SDP. This difference concerns payload format only, but not the actual codec. It is not a difference
 | 
								return false;
 | 
				
			||||||
	 * within the meaning of this function. */
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -429,7 +417,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
 | 
				
			|||||||
	if (!codec_src)
 | 
						if (!codec_src)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Use the codec information from the source and try to find the
 | 
						/* Use the codec infrmation from the source and try to find the
 | 
				
			||||||
	 * equivalent of it on the destination side */
 | 
						 * equivalent of it on the destination side */
 | 
				
			||||||
	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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,14 +30,12 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_iuup.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 <osmocom/core/timer.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "conn_rtp",
 | 
						.group_name_prefix = "conn_rtp",
 | 
				
			||||||
	.group_description = "rtp connection statistics",
 | 
						.group_description = "rtp connection statistics",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -95,36 +93,30 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
 | 
				
			|||||||
	static atomic_uint rate_ctr_index = 0;
 | 
						static atomic_uint rate_ctr_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
						conn_rtp->type = MGCP_RTP_DEFAULT;
 | 
				
			||||||
 | 
						conn_rtp->osmux.cid_allocated = false;
 | 
				
			||||||
	/* Osmux specific defaults, only used if conn is later on Osmux-enabled: */
 | 
						conn_rtp->osmux.cid = 0;
 | 
				
			||||||
	conn_rtp->osmux.state = OSMUX_STATE_DISABLED;
 | 
					 | 
				
			||||||
	conn_rtp->osmux.local_cid_allocated = false;
 | 
					 | 
				
			||||||
	conn_rtp->osmux.local_cid = 0;
 | 
					 | 
				
			||||||
	conn_rtp->osmux.remote_cid_present = false;
 | 
					 | 
				
			||||||
	conn_rtp->osmux.remote_cid = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* backpointer to the generic part of the connection */
 | 
						/* backpointer to the generic part of the connection */
 | 
				
			||||||
	conn->u.rtp.conn = conn;
 | 
						conn->u.rtp.conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	end->rtp.fd = -1;
 | 
						end->rtp.fd = -1;
 | 
				
			||||||
	end->rtcp.fd = -1;
 | 
						end->rtcp.fd = -1;
 | 
				
			||||||
	memset(&end->addr, 0, sizeof(end->addr));
 | 
						end->rtp_port = end->rtcp_port = 0;
 | 
				
			||||||
	end->rtcp_port = 0;
 | 
					 | 
				
			||||||
	talloc_free(end->fmtp_extra);
 | 
						talloc_free(end->fmtp_extra);
 | 
				
			||||||
	end->fmtp_extra = NULL;
 | 
						end->fmtp_extra = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set default values */
 | 
						/* Set default values */
 | 
				
			||||||
	end->frames_per_packet = 0;	/* unknown */
 | 
						end->frames_per_packet = 0;	/* unknown */
 | 
				
			||||||
	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
						end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
 | 
				
			||||||
	end->output_enabled = false;
 | 
						end->output_enabled = 0;
 | 
				
			||||||
	end->maximum_packet_time = -1;
 | 
						end->maximum_packet_time = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->ctrg = 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->ctrg)
 | 
						if (!conn_rtp->rate_ctr_group)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR);
 | 
						conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure codec table is reset */
 | 
						/* Make sure codec table is reset */
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
@@ -137,10 +129,8 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
						if (mgcp_conn_rtp_is_osmux(conn_rtp))
 | 
				
			||||||
		conn_osmux_disable(conn_rtp);
 | 
							conn_osmux_disable(conn_rtp);
 | 
				
			||||||
	if (mgcp_conn_rtp_is_iuup(conn_rtp))
 | 
					 | 
				
			||||||
		mgcp_conn_iuup_cleanup(conn_rtp);
 | 
					 | 
				
			||||||
	mgcp_free_rtp_port(&conn_rtp->end);
 | 
						mgcp_free_rtp_port(&conn_rtp->end);
 | 
				
			||||||
	rate_ctr_group_free(conn_rtp->ctrg);
 | 
						rate_ctr_group_free(conn_rtp->rate_ctr_group);
 | 
				
			||||||
	mgcp_codec_reset_all(conn_rtp);
 | 
						mgcp_codec_reset_all(conn_rtp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -269,7 +259,7 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
					static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
	struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
 | 
						struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (all_stats == NULL || conn_stats == NULL)
 | 
						if (all_stats == NULL || conn_stats == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -335,11 +325,6 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*! free all connections at once.
 | 
					/*! free all connections at once.
 | 
				
			||||||
 *  \param[in] endp associated endpoint */
 | 
					 *  \param[in] endp associated endpoint */
 | 
				
			||||||
#if defined(__has_attribute)
 | 
					 | 
				
			||||||
#if __has_attribute(no_sanitize)
 | 
					 | 
				
			||||||
__attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
					void mgcp_conn_free_all(struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
@@ -366,39 +351,15 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						switch (conn->type) {
 | 
				
			||||||
	case MGCP_CONN_TYPE_RTP:
 | 
						case MGCP_CONN_TYPE_RTP:
 | 
				
			||||||
		switch (conn->u.rtp.type) {
 | 
					 | 
				
			||||||
		case MGCP_RTP_DEFAULT:
 | 
					 | 
				
			||||||
		/* Dump RTP connection */
 | 
							/* Dump RTP connection */
 | 
				
			||||||
		snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
							snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
 | 
				
			||||||
			 "rtp:%u rtcp:%u)",
 | 
								 "rtp:%u rtcp:%u)",
 | 
				
			||||||
				conn->name, conn->id,
 | 
								 conn->name,
 | 
				
			||||||
 | 
								 conn->id,
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
								 osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
								 ntohs(conn->u.rtp.end.rtp_port),
 | 
				
			||||||
			 ntohs(conn->u.rtp.end.rtcp_port));
 | 
								 ntohs(conn->u.rtp.end.rtcp_port));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
		case MGCP_RTP_OSMUX:
 | 
					 | 
				
			||||||
			snprintf(str, sizeof(str), "(%s/osmux, id:0x%s, ip:%s, "
 | 
					 | 
				
			||||||
				"port:%u CID:%u)",
 | 
					 | 
				
			||||||
				conn->name, conn->id,
 | 
					 | 
				
			||||||
				osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa),
 | 
					 | 
				
			||||||
				conn->u.rtp.osmux.local_cid);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case MGCP_RTP_IUUP:
 | 
					 | 
				
			||||||
			snprintf(str, sizeof(str), "(%s/iuup, id:0x%s, ip:%s, "
 | 
					 | 
				
			||||||
				"port:%u)",
 | 
					 | 
				
			||||||
				conn->name, conn->id,
 | 
					 | 
				
			||||||
				osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
				osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			/* Should not happen, we should be able to dump
 | 
					 | 
				
			||||||
			 * every possible connection type. */
 | 
					 | 
				
			||||||
			snprintf(str, sizeof(str), "(unknown conn_rtp connection type %u)",
 | 
					 | 
				
			||||||
				 conn->u.rtp.type);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* Should not happen, we should be able to dump
 | 
							/* Should not happen, we should be able to dump
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								src/libosmo-mgcp/mgcp_ctrl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/libosmo-mgcp/mgcp_ctrl.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) 2020 by Harald Welte <laforge@gnumonks.org>
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
 | 
				
			||||||
 | 
									void **node_data, int *i)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
 | 
				
			||||||
 | 
										     const char *bind_addr, uint16_t port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
 | 
				
			||||||
 | 
										   _LAST_CTRL_NODE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -338,7 +338,6 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
	trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
 | 
						trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
 | 
				
			||||||
	if (!trunk) {
 | 
						if (!trunk) {
 | 
				
			||||||
		LOGP(DE1, LOGL_ERROR, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
 | 
							LOGP(DE1, LOGL_ERROR, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -360,9 +359,6 @@ static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Trigger sending of pending E1 traffic */
 | 
						/* Trigger sending of pending E1 traffic */
 | 
				
			||||||
	e1_send(ts, trunk);
 | 
						e1_send(ts, trunk);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* e1inp_rx_ts() does not free() msgb */
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
					static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
 | 
				
			||||||
@@ -496,7 +492,7 @@ static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Equip E1 endpoint with I.460 mux resources.
 | 
					/* !Equip E1 endpoint with I.460 mux resources.
 | 
				
			||||||
 *  \param[in] endp endpoint to equip
 | 
					 *  \param[in] endp endpoint to equip
 | 
				
			||||||
 *  \param[in] ts E1 timeslot number.
 | 
					 *  \param[in] ts E1 timeslot number.
 | 
				
			||||||
 *  \param[in] ss E1 subslot number.
 | 
					 *  \param[in] ss E1 subslot number.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -224,9 +224,9 @@ static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Find an endpoint of a trunk specified by its name.
 | 
					/*! Find an endpoint of a trunk specified by its name.
 | 
				
			||||||
 *  \param[in] epname endpoint name to check.
 | 
					 *  \param[in] epname endpoint name to check
 | 
				
			||||||
 *  \param[in] trunk mgcp_trunk that might have this endpoint.
 | 
					 *  \param[in] trunk mgcp_trunk that might have this endpoint
 | 
				
			||||||
 *  \returns NULL if no ep found, else endpoint. */
 | 
					 *  \returns NULL if no ep found, else endpoint */
 | 
				
			||||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
					struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
 | 
				
			||||||
						    const struct mgcp_trunk *trunk)
 | 
											    const struct mgcp_trunk *trunk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,753 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					 | 
				
			||||||
 * All rights not specifically granted under this license are reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Author: Pau Espin Pedrol
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/core/byteswap.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/gsm/iuup.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/netif/rtp.h>
 | 
					 | 
				
			||||||
#include <osmocom/netif/amr.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_iuup.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_network.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/debug.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MGW_IUUP_MSGB_SIZE 4096
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct osmo_iuup_rnl_config def_configure_req = {
 | 
					 | 
				
			||||||
	.transparent = false,
 | 
					 | 
				
			||||||
	.active = true,
 | 
					 | 
				
			||||||
	.supported_versions_mask = 0x0003,
 | 
					 | 
				
			||||||
	.num_rfci = 0,
 | 
					 | 
				
			||||||
	.num_subflows = 0,
 | 
					 | 
				
			||||||
	.IPTIs_present = false,
 | 
					 | 
				
			||||||
	.t_init = { .t_ms = IUUP_TIMER_INIT_T_DEFAULT, .n_max = IUUP_TIMER_INIT_N_DEFAULT },
 | 
					 | 
				
			||||||
	.t_ta = { .t_ms = IUUP_TIMER_TA_T_DEFAULT, .n_max = IUUP_TIMER_TA_N_DEFAULT },
 | 
					 | 
				
			||||||
	.t_rc = { .t_ms = IUUP_TIMER_RC_T_DEFAULT, .n_max = IUUP_TIMER_RC_N_DEFAULT },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Find a destination connection. */
 | 
					 | 
				
			||||||
static struct mgcp_conn *_find_dst_conn(struct mgcp_conn *conn)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* NOTE: This code path runs every time an RTP packet is received. The
 | 
					 | 
				
			||||||
	 * function mgcp_find_dst_conn() we use to determine the detination
 | 
					 | 
				
			||||||
	 * connection will iterate the connection list inside the endpoint.
 | 
					 | 
				
			||||||
	 * Since list iterations are quite costly, we will figure out the
 | 
					 | 
				
			||||||
	 * destination only once and use the optional private data pointer of
 | 
					 | 
				
			||||||
	 * the connection to cache the destination connection pointer. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
					 | 
				
			||||||
	if (!conn->priv) {
 | 
					 | 
				
			||||||
		conn_dst = mgcp_find_dst_conn(conn);
 | 
					 | 
				
			||||||
		conn->priv = conn_dst;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		conn_dst = (struct mgcp_conn *)conn->priv;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return conn_dst;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Find RFCI containing all 0 sizes, -1 if not found. irp is an Initialization.ind prim */
 | 
					 | 
				
			||||||
static int _find_rfci_no_data(struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	uint8_t rfci_cnt = 0;
 | 
					 | 
				
			||||||
	/* Find RFCI containing NO_DATA: */
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
					 | 
				
			||||||
		struct osmo_iuup_rfci *rfci = &irp->u.status.u.initialization.rfci[i];
 | 
					 | 
				
			||||||
		int j;
 | 
					 | 
				
			||||||
		bool is_no_data;
 | 
					 | 
				
			||||||
		if (!rfci->used)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		rfci_cnt++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		is_no_data = true;
 | 
					 | 
				
			||||||
		for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++) {
 | 
					 | 
				
			||||||
			if (rfci->subflow_sizes[j]) {
 | 
					 | 
				
			||||||
				is_no_data = false;
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (is_no_data)
 | 
					 | 
				
			||||||
			return rfci->id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* early loop termination: */
 | 
					 | 
				
			||||||
		if (rfci_cnt == irp->u.status.u.initialization.num_subflows)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Lookup RFCI to use for specific AMR codec type. -1 if none found */
 | 
					 | 
				
			||||||
static int8_t _conn_iuup_amr_ft_2_rfci(struct mgcp_conn_rtp *conn_rtp, uint8_t ft)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int8_t i;
 | 
					 | 
				
			||||||
	uint8_t rfci_cnt = 0;
 | 
					 | 
				
			||||||
	unsigned match_bytes = (unsigned)osmo_amr_bytes(ft);
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp = conn_rtp->iuup.init_ind;
 | 
					 | 
				
			||||||
	if (!irp) {
 | 
					 | 
				
			||||||
		/* No IuUP Initialization has occured on the IuUP side yet. Return error and drop the RTP data, until
 | 
					 | 
				
			||||||
		 * the IuUP Initialization has configured the link. */
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO: cache this somehow */
 | 
					 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(irp->u.status.u.initialization.rfci); i++) {
 | 
					 | 
				
			||||||
		struct osmo_iuup_rfci *rfci = &irp->u.status.u.initialization.rfci[i];
 | 
					 | 
				
			||||||
		int j;
 | 
					 | 
				
			||||||
		unsigned num_bits;
 | 
					 | 
				
			||||||
		if (!rfci->used)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		rfci_cnt++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		num_bits = 0;
 | 
					 | 
				
			||||||
		for (j = 0; j < irp->u.status.u.initialization.num_subflows; j++)
 | 
					 | 
				
			||||||
			num_bits += rfci->subflow_sizes[j];
 | 
					 | 
				
			||||||
		if (match_bytes == (num_bits + 7)/8)
 | 
					 | 
				
			||||||
			return rfci->id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* early loop termination: */
 | 
					 | 
				
			||||||
		if (rfci_cnt == irp->u.status.u.initialization.num_subflows)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Helper function to configure IuUP layer FSM as Init-Passive, based on default config */
 | 
					 | 
				
			||||||
static int _conn_iuup_configure_as_passive(struct mgcp_conn_rtp *conn_rtp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_rtp->iuup.active_init = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Tx CONFIG.req */
 | 
					 | 
				
			||||||
	irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
					 | 
				
			||||||
	irp->u.config = def_configure_req;
 | 
					 | 
				
			||||||
	irp->u.config.active = conn_rtp->iuup.active_init;
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) == 0)
 | 
					 | 
				
			||||||
		conn_rtp->iuup.configured = true;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Helper function to configure IuUP layer FSM as Init-Active, based on received
 | 
					 | 
				
			||||||
 * RNL Status-Init primitive from the sister IuUP connection we will bridge to. */
 | 
					 | 
				
			||||||
static int _conn_iuup_configure_as_active(struct mgcp_conn_rtp *conn_rtp, struct osmo_iuup_rnl_prim *init_ind)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp = init_ind;
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp2;
 | 
					 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	bool prev_output_enabled;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_rtp->iuup.active_init = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Find RFCI containing NO_DATA: */
 | 
					 | 
				
			||||||
	conn_rtp->iuup.rfci_id_no_data = _find_rfci_no_data(init_ind);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Copy over the rfci_id_no_data, since we reuse the same subflow set: */
 | 
					 | 
				
			||||||
	msg = msgb_copy_c(conn_rtp->conn, irp->oph.msg, "iuup-init-copy");
 | 
					 | 
				
			||||||
	conn_rtp->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
 | 
					 | 
				
			||||||
	conn_rtp->iuup.init_ind->oph.msg = msg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Tx CONFIG.req */
 | 
					 | 
				
			||||||
	irp2 = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_CONFIG, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
					 | 
				
			||||||
	irp2->u.config.transparent = false;
 | 
					 | 
				
			||||||
	irp2->u.config.active = conn_rtp->iuup.active_init;
 | 
					 | 
				
			||||||
	irp2->u.config.data_pdu_type = irp->u.status.u.initialization.data_pdu_type;
 | 
					 | 
				
			||||||
	irp2->u.config.supported_versions_mask = def_configure_req.supported_versions_mask;
 | 
					 | 
				
			||||||
	irp2->u.config.num_rfci = irp->u.status.u.initialization.num_rfci;
 | 
					 | 
				
			||||||
	irp2->u.config.num_subflows = irp->u.status.u.initialization.num_subflows;
 | 
					 | 
				
			||||||
	irp2->u.config.IPTIs_present = irp->u.status.u.initialization.IPTIs_present;
 | 
					 | 
				
			||||||
	memcpy(irp2->u.config.rfci, irp->u.status.u.initialization.rfci, sizeof(irp2->u.config.rfci));
 | 
					 | 
				
			||||||
	irp2->u.config.t_init = def_configure_req.t_init;
 | 
					 | 
				
			||||||
	irp2->u.config.t_ta = def_configure_req.t_ta;
 | 
					 | 
				
			||||||
	irp2->u.config.t_rc = def_configure_req.t_rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We need to force allowance of RTP containing Init-ACK back: */
 | 
					 | 
				
			||||||
	prev_output_enabled = conn_rtp->end.output_enabled;
 | 
					 | 
				
			||||||
	conn_rtp->end.output_enabled = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp2)) == 0)
 | 
					 | 
				
			||||||
		conn_rtp->iuup.configured = true;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed configuring IuUP layer\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_rtp->end.output_enabled = prev_output_enabled;
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Helper function to push an RTP+IuUP pkt up to the IuUP layer FSM through the
 | 
					 | 
				
			||||||
 * TNL primitive interface. */
 | 
					 | 
				
			||||||
static int _conn_iuup_rtp_pl_up(struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* Send RTP payload (IuUP) up the stack: */
 | 
					 | 
				
			||||||
	struct osmo_iuup_tnl_prim *itp;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg->l2h = msgb_data(msg) + sizeof(struct rtp_hdr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	itp = osmo_iuup_tnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_TNL_UNITDATA, PRIM_OP_INDICATION, MGW_IUUP_MSGB_SIZE);
 | 
					 | 
				
			||||||
	itp->oph.msg->l2h = msgb_put(itp->oph.msg, msgb_l2len(msg));
 | 
					 | 
				
			||||||
	memcpy(itp->oph.msg->l2h, msgb_l2(msg), msgb_l2len(msg));
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_tnl_prim_up(conn_rtp->iuup.iui, itp)) != 0) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed passing IuUP-Init to IuUP layer\n");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int check_rtp_iuup(const struct mgcp_conn_rtp *conn_rtp, struct msgb *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t min_size = sizeof(struct rtp_hdr);
 | 
					 | 
				
			||||||
	/* Check there's at least 2 bytes of RTP payload (IuUP header). This is
 | 
					 | 
				
			||||||
	 ** mainly to avoid 0-byte payload copy cases */
 | 
					 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr) + 2) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "RTP-IuUP packet too short (%u < %zu)\n",
 | 
					 | 
				
			||||||
			     msgb_length(msg), min_size);
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an IuUP sister
 | 
					 | 
				
			||||||
 * conn in the endpoint. The function takes ownsership of the irp */
 | 
					 | 
				
			||||||
static int bridge_iuup_to_iuup_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If we are not configured and we received bridged data, it means
 | 
					 | 
				
			||||||
	 * conn_rtp_src is already configured and INITed, and we can infer
 | 
					 | 
				
			||||||
	 * conn_rtp_src is Init-passive (RNC side), so conn_rtp_dst needs to be
 | 
					 | 
				
			||||||
	 * configured as INIT-active: */
 | 
					 | 
				
			||||||
	if (!conn_rtp_dst->iuup.configured) {
 | 
					 | 
				
			||||||
		OSMO_ASSERT(conn_rtp_src->iuup.init_ind);
 | 
					 | 
				
			||||||
		rc = _conn_iuup_configure_as_active(conn_rtp_dst, conn_rtp_src->iuup.init_ind);
 | 
					 | 
				
			||||||
		if (rc < 0) {
 | 
					 | 
				
			||||||
			msgb_free(irp->oph.msg);
 | 
					 | 
				
			||||||
			return rc;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We simply forward the msg, without freeing it: */
 | 
					 | 
				
			||||||
	talloc_steal(conn_rtp_dst->conn, irp->oph.msg);
 | 
					 | 
				
			||||||
	irp->oph.operation = PRIM_OP_REQUEST;
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_rnl_prim_down(conn_rtp_dst->iuup.iui, irp)) != 0)
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp_dst, LOGL_ERROR, "Failed Tx data down to IuUP layer\n");
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Bridge received IuUP packet in conn_rtp_src to conn_rtp_dst, an RTP (no IuUP)
 | 
					 | 
				
			||||||
 * sister conn in the endpoint. The function takes ownsership of the irp */
 | 
					 | 
				
			||||||
static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mgcp_conn_rtp *conn_rtp_dst, struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* FIXME: We probably need transcoding here?! Or at least look up AMR modes and translate to related RFCI */
 | 
					 | 
				
			||||||
	uint8_t frame_nr = irp->u.data.frame_nr;
 | 
					 | 
				
			||||||
	uint8_t fqc = irp->u.data.fqc;
 | 
					 | 
				
			||||||
	struct msgb *msg = irp->oph.msg;
 | 
					 | 
				
			||||||
	ssize_t amr_length = 0;
 | 
					 | 
				
			||||||
	int ft;
 | 
					 | 
				
			||||||
	uint8_t *amr_data;
 | 
					 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
					 | 
				
			||||||
	struct amr_hdr *amr_hdr;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ft = osmo_amr_bytes_to_ft(msgb_l3len(msg));
 | 
					 | 
				
			||||||
	if (ft < 0) {
 | 
					 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "Unknown AMR format for size %u\n", msgb_l3len(msg));
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		return ft;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	msgb_pull_to_l3(msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg));
 | 
					 | 
				
			||||||
		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr));
 | 
					 | 
				
			||||||
		amr_hdr->cmr = 15; /* no change */
 | 
					 | 
				
			||||||
		amr_hdr->f = 0;
 | 
					 | 
				
			||||||
		amr_hdr->q = !fqc;
 | 
					 | 
				
			||||||
		amr_hdr->ft = ft & 0xff;
 | 
					 | 
				
			||||||
		amr_hdr->pad1 = 0;
 | 
					 | 
				
			||||||
		amr_hdr->pad2 = 0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		OSMO_ASSERT(msgb_tailroom(msg) >= 2);
 | 
					 | 
				
			||||||
		msgb_put(msg, 2);
 | 
					 | 
				
			||||||
		osmo_amr_iuup_to_bwe(msgb_data(msg), msgb_length(msg) - 2, msgb_length(msg) + 2);
 | 
					 | 
				
			||||||
		/* fill bwe header */
 | 
					 | 
				
			||||||
		amr_data = msgb_data(msg);
 | 
					 | 
				
			||||||
		/* CMR no change      | follow bit | ft (3 of 4 bits) */
 | 
					 | 
				
			||||||
		amr_data[0] = 15 << 4 | (0 << 3) | (ft >> 1);
 | 
					 | 
				
			||||||
		amr_data[1] |= ((ft & 0x1) << 7) | (((!fqc) & 0x1) << 6);
 | 
					 | 
				
			||||||
		amr_length = (osmo_amr_bits(ft) + 10 + 7) / 8;
 | 
					 | 
				
			||||||
		msgb_trim(msg, amr_length);
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR BE: ft %d, len %zd\n", ft, amr_length);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *) msgb_push(msg, sizeof(*rtp_hdr));
 | 
					 | 
				
			||||||
	*rtp_hdr = (struct rtp_hdr){
 | 
					 | 
				
			||||||
		.csrc_count = 0,
 | 
					 | 
				
			||||||
		.extension = 0,
 | 
					 | 
				
			||||||
		.padding = 0,
 | 
					 | 
				
			||||||
		.version = 0,
 | 
					 | 
				
			||||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
					 | 
				
			||||||
		.marker = 0,
 | 
					 | 
				
			||||||
		.sequence = frame_nr,
 | 
					 | 
				
			||||||
		.timestamp = 0,
 | 
					 | 
				
			||||||
		.ssrc = 0
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = mgcp_send(conn_rtp_dst->conn->endp, true, NULL, msg, conn_rtp_src, conn_rtp_dst);
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handle RNL Data primitive received from the IuUP layer FSM: Bridge it to the
 | 
					 | 
				
			||||||
 * sister connection in the endpoint: */
 | 
					 | 
				
			||||||
static int _conn_iuup_rx_rnl_data(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_rtp_dst;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_dst = _find_dst_conn(conn_rtp_src->conn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* There is no destination conn, stop here */
 | 
					 | 
				
			||||||
	if (!conn_dst) {
 | 
					 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
			 "no connection to forward an incoming IuUP payload to\n");
 | 
					 | 
				
			||||||
		rc = -1;
 | 
					 | 
				
			||||||
		goto free_ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The destination conn is not an RTP/IuUP connection */
 | 
					 | 
				
			||||||
	if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
 | 
					 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "unable to find suitable destination conn\n");
 | 
					 | 
				
			||||||
		 rc = -1;
 | 
					 | 
				
			||||||
		goto free_ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	conn_rtp_dst = &conn_dst->u.rtp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (conn_rtp_dst->type) {
 | 
					 | 
				
			||||||
	case MGCP_RTP_IUUP:
 | 
					 | 
				
			||||||
		return bridge_iuup_to_iuup_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
					 | 
				
			||||||
	case MGCP_RTP_DEFAULT:
 | 
					 | 
				
			||||||
		return bridge_iuup_to_rtp_peer(conn_rtp_src, conn_rtp_dst, irp);
 | 
					 | 
				
			||||||
	case MGCP_RTP_OSMUX:
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_ERROR,
 | 
					 | 
				
			||||||
			 "Forward of IuUP payload to RTP connection type %u not supported!\n",
 | 
					 | 
				
			||||||
			 conn_rtp_dst->type);
 | 
					 | 
				
			||||||
		rc = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
free_ret:
 | 
					 | 
				
			||||||
	msgb_free(irp->oph.msg);
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handle RNL Status-Init primitive received from the IuUP layer FSM.
 | 
					 | 
				
			||||||
 * Potentially configure sister conn as IuUP Init-Active: */
 | 
					 | 
				
			||||||
static int _conn_iuup_rx_rnl_status_init(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_dst;
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_rtp_dst;
 | 
					 | 
				
			||||||
	int rc = 0;
 | 
					 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn_rtp_src->iuup.init_ind) {
 | 
					 | 
				
			||||||
		/* We received more than one IuUP Initialization. It's probably
 | 
					 | 
				
			||||||
		 * a retransmission, so simply ignore it (lower layers take care
 | 
					 | 
				
			||||||
		 * of ACKing it). */
 | 
					 | 
				
			||||||
		LOGPCONN(conn_rtp_src->conn, DRTP, LOGL_INFO,
 | 
					 | 
				
			||||||
		  "Ignoring potential IuUP Initialization retrans\n");
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg = msgb_copy_c(conn_rtp_src->conn, irp->oph.msg, "iuup-init-copy");
 | 
					 | 
				
			||||||
	conn_rtp_src->iuup.init_ind = (struct osmo_iuup_rnl_prim *)msgb_data(msg);
 | 
					 | 
				
			||||||
	conn_rtp_src->iuup.init_ind->oph.msg = msg;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Find RFCI containing NO_DATA: */
 | 
					 | 
				
			||||||
	conn_rtp_src->iuup.rfci_id_no_data = _find_rfci_no_data(irp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn_dst = _find_dst_conn(conn_rtp_src->conn);
 | 
					 | 
				
			||||||
	/* If not yet there, peer will potentially be IuUP-Initialized later
 | 
					 | 
				
			||||||
	 * when we attempt to bridge audio towards it. See bridge_iuup_to_iuup_peer() */
 | 
					 | 
				
			||||||
	if (!conn_dst)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	conn_rtp_dst = &conn_dst->u.rtp;
 | 
					 | 
				
			||||||
	if (!mgcp_conn_rtp_is_iuup(conn_rtp_dst))
 | 
					 | 
				
			||||||
		return 0; /* Nothing to do */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We received IuUP parameters on the peer (RNC), Init actively this conn (against CN): */
 | 
					 | 
				
			||||||
	if (!conn_rtp_dst->iuup.configured)
 | 
					 | 
				
			||||||
		rc = _conn_iuup_configure_as_active(conn_rtp_dst, irp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Handle RNL Status primitives received from the IuUP layer FSM: */
 | 
					 | 
				
			||||||
static int _conn_iuup_rx_rnl_status(struct mgcp_conn_rtp *conn_rtp_src, struct osmo_iuup_rnl_prim *irp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (irp->u.status.procedure) {
 | 
					 | 
				
			||||||
	case IUUP_PROC_INIT:
 | 
					 | 
				
			||||||
		rc = _conn_iuup_rx_rnl_status_init(conn_rtp_src, irp);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case IUUP_PROC_RATE_CTRL:
 | 
					 | 
				
			||||||
	case IUUP_PROC_TIME_ALIGN:
 | 
					 | 
				
			||||||
	case IUUP_PROC_ERR_EVENT:
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp_src, LOGL_ERROR,
 | 
					 | 
				
			||||||
			     "Received IuUP RNL STATUS procedure type %u not handled\n",
 | 
					 | 
				
			||||||
			     irp->u.status.procedure);
 | 
					 | 
				
			||||||
		rc = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Received RNL primitive from the IuUP layer FSM containing IuUP Status or
 | 
					 | 
				
			||||||
 * data. Continue pushing it up the stack, either IuUP Status or Data: */
 | 
					 | 
				
			||||||
static int _conn_iuup_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_rtp_src = ctx;
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp = (struct osmo_iuup_rnl_prim *)oph;
 | 
					 | 
				
			||||||
	struct msgb *msg = oph->msg;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (OSMO_PRIM_HDR(&irp->oph)) {
 | 
					 | 
				
			||||||
	case OSMO_PRIM(OSMO_IUUP_RNL_DATA, PRIM_OP_INDICATION):
 | 
					 | 
				
			||||||
		/* we pass ownsership of msg here: */
 | 
					 | 
				
			||||||
		rc = _conn_iuup_rx_rnl_data(conn_rtp_src, irp);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case OSMO_PRIM(OSMO_IUUP_RNL_STATUS, PRIM_OP_INDICATION):
 | 
					 | 
				
			||||||
		rc = _conn_iuup_rx_rnl_status(conn_rtp_src, irp);
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		msgb_free(msg);
 | 
					 | 
				
			||||||
		OSMO_ASSERT(false);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Send |RTP+IuUP| data down the stack of the specified destination connection.
 | 
					 | 
				
			||||||
 *  \param[in] endp associated endpoint (for configuration, logging).
 | 
					 | 
				
			||||||
 *  \param[in] buf buffer that contains the |RTP+IuUP| data.
 | 
					 | 
				
			||||||
 *  \param[in] len length of the buffer that contains the |RTP+IuUP| data.
 | 
					 | 
				
			||||||
 *  \param[in] conn_src associated source connection.
 | 
					 | 
				
			||||||
 *  \param[in] conn_dst associated destination connection.
 | 
					 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR. */
 | 
					 | 
				
			||||||
static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
					 | 
				
			||||||
		   struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/*! When no destination connection is available (e.g. when only one
 | 
					 | 
				
			||||||
	 *  connection in loopback mode exists), then the source connection
 | 
					 | 
				
			||||||
	 *  shall be specified as destination connection */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct mgcp_rtp_end *rtp_end;
 | 
					 | 
				
			||||||
	struct mgcp_rtp_state *rtp_state;
 | 
					 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
					 | 
				
			||||||
	struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
					 | 
				
			||||||
	int buflen = msgb_length(msg);
 | 
					 | 
				
			||||||
	char *dest_name;
 | 
					 | 
				
			||||||
	int len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn_src);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn_dst);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering IuUP packet...\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Note: In case of loopback configuration, both, the source and the
 | 
					 | 
				
			||||||
	 * destination will point to the same connection. */
 | 
					 | 
				
			||||||
	rtp_end = &conn_dst->end;
 | 
					 | 
				
			||||||
	rtp_state = &conn_src->state;
 | 
					 | 
				
			||||||
	dest_name = conn_dst->conn->name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Ensure we have an alternative SSRC in case we need it, see also
 | 
					 | 
				
			||||||
	 * gen_rtp_header() */
 | 
					 | 
				
			||||||
	if (rtp_state->alt_rtp_tx_ssrc == 0)
 | 
					 | 
				
			||||||
		rtp_state->alt_rtp_tx_ssrc = rand();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!rtp_end->output_enabled) {
 | 
					 | 
				
			||||||
		rtpconn_rate_ctr_add(conn_dst, endp, RTP_DROPPED_PACKETS_CTR, 1);
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
			 "output disabled, drop to %s %s "
 | 
					 | 
				
			||||||
			 "rtp_port:%u rtcp_port:%u\n",
 | 
					 | 
				
			||||||
			 dest_name,
 | 
					 | 
				
			||||||
			 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Specs say, in IuUP, the RTP seqnum and timestamp should actually be
 | 
					 | 
				
			||||||
	 * ignored by the receiver, but still it's useful for debug purposes
 | 
					 | 
				
			||||||
	 * to set it. Moreover, it seems ip.access nano3g produces much worse
 | 
					 | 
				
			||||||
	 * audio output on the air side if timestamp is not set properly. */
 | 
					 | 
				
			||||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
					 | 
				
			||||||
	hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence);
 | 
					 | 
				
			||||||
	hdr->ssrc = rtp_state->alt_rtp_tx_ssrc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
		 "process/send IuUP to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
					 | 
				
			||||||
		 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
					 | 
				
			||||||
		 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
					 | 
				
			||||||
	forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
					 | 
				
			||||||
		     msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, (char *)hdr, buflen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (len <= 0)
 | 
					 | 
				
			||||||
		return len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_dst, endp, RTP_PACKETS_TX_CTR, 1);
 | 
					 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
					 | 
				
			||||||
	rtp_state->alt_rtp_tx_sequence++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return len;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Received TNL primitive from IuUP layer FSM, transmit it further down to the
 | 
					 | 
				
			||||||
 * socket towards destination peer. */
 | 
					 | 
				
			||||||
static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_rtp_dst = ctx;
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_dst = conn_rtp_dst->conn;
 | 
					 | 
				
			||||||
	struct osmo_iuup_tnl_prim *itp = (struct osmo_iuup_tnl_prim *)oph;
 | 
					 | 
				
			||||||
	struct mgcp_conn *conn_src;
 | 
					 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	struct rtp_hdr *rtph;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(OSMO_PRIM_HDR(&itp->oph) == OSMO_PRIM(OSMO_IUUP_TNL_UNITDATA, PRIM_OP_REQUEST));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msg = oph->msg;
 | 
					 | 
				
			||||||
	talloc_steal(conn_rtp_dst->conn, msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	msgb_pull_to_l2(msg);
 | 
					 | 
				
			||||||
	rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph));
 | 
					 | 
				
			||||||
	/* TODO: fill rtph properly: */
 | 
					 | 
				
			||||||
	*rtph = (struct rtp_hdr){
 | 
					 | 
				
			||||||
		.csrc_count = 0,
 | 
					 | 
				
			||||||
		.extension = 0,
 | 
					 | 
				
			||||||
		.padding = 0,
 | 
					 | 
				
			||||||
		.version = 2,
 | 
					 | 
				
			||||||
		.payload_type = conn_rtp_dst->end.codec->payload_type,
 | 
					 | 
				
			||||||
		.marker = 0,
 | 
					 | 
				
			||||||
		.sequence = 0,
 | 
					 | 
				
			||||||
		.timestamp = 0,
 | 
					 | 
				
			||||||
		.ssrc = 0
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* The destination of the destination conn is the source conn, right? */
 | 
					 | 
				
			||||||
	conn_src = _find_dst_conn(conn_dst);
 | 
					 | 
				
			||||||
	if (!conn_src) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp_dst, LOGL_NOTICE,
 | 
					 | 
				
			||||||
			     "Couldn't find source conn for IuUP dst conn\n");
 | 
					 | 
				
			||||||
		/* If there's no sister connection we are either still
 | 
					 | 
				
			||||||
		 * initializing (so we want to send back Init (ACK)), or we are
 | 
					 | 
				
			||||||
		 * probably in loopback mode anyway, so use dst as src. */
 | 
					 | 
				
			||||||
		conn_src = conn_dst;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return mgcp_send_iuup(conn_dst->endp, msg, &conn_src->u.rtp, conn_rtp_dst);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Used to upgrade a regular RTP connection (MGCP_RTP_DEFAULT) to become a IuUP
 | 
					 | 
				
			||||||
 * connection (MGCP_RTP_IUUP) */
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_init(struct mgcp_conn_rtp *conn_rtp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	conn_rtp->type = MGCP_RTP_IUUP;
 | 
					 | 
				
			||||||
	conn_rtp->iuup.iui = osmo_iuup_instance_alloc(conn_rtp->conn, conn_rtp->conn->id);
 | 
					 | 
				
			||||||
	OSMO_ASSERT(conn_rtp->iuup.iui);
 | 
					 | 
				
			||||||
	osmo_iuup_instance_set_user_prim_cb(conn_rtp->iuup.iui, _conn_iuup_user_prim_cb, conn_rtp);
 | 
					 | 
				
			||||||
	osmo_iuup_instance_set_transport_prim_cb(conn_rtp->iuup.iui, _conn_iuup_transport_prim_cb, conn_rtp);
 | 
					 | 
				
			||||||
	conn_rtp->iuup.rfci_id_no_data = -1;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Cleanup specific IuUP connection (MGCP_RTP_IUUP) state, allocated by mgcp_conn_iuup_init() */
 | 
					 | 
				
			||||||
void mgcp_conn_iuup_cleanup(struct mgcp_conn_rtp *conn_rtp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	osmo_iuup_instance_free(conn_rtp->iuup.iui);
 | 
					 | 
				
			||||||
	conn_rtp->iuup.iui = NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Received RTP+IuUP pkt from socket of conn_rtp_src, build a TNL primitive to
 | 
					 | 
				
			||||||
 * push it further up the stack to the IuUP layer FSM to handle and/or bridge it */
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_dispatch_rtp(struct msgb *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
					 | 
				
			||||||
	struct mgcp_conn_rtp *conn_rtp_src = mc->conn_src;
 | 
					 | 
				
			||||||
	int rc = 0;
 | 
					 | 
				
			||||||
	bool force_output_enabled = false;
 | 
					 | 
				
			||||||
	bool prev_output_enabled;
 | 
					 | 
				
			||||||
	struct osmo_sockaddr prev_rem_addr;
 | 
					 | 
				
			||||||
	uint16_t prev_rem_rtp_port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	OSMO_ASSERT(mgcp_conn_rtp_is_iuup(conn_rtp_src));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((rc = check_rtp_iuup(conn_rtp_src, msg)) < 0)
 | 
					 | 
				
			||||||
		goto free_ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!conn_rtp_src->iuup.configured) {
 | 
					 | 
				
			||||||
		/* We received the first message without sending any, the peer is the active side (RNC). */
 | 
					 | 
				
			||||||
		rc = _conn_iuup_configure_as_passive(conn_rtp_src);
 | 
					 | 
				
			||||||
		if (rc < 0)
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		/* We need to force allowance of RTP containing Init-ACK back: */
 | 
					 | 
				
			||||||
		prev_output_enabled = conn_rtp_src->end.output_enabled;
 | 
					 | 
				
			||||||
		conn_rtp_src->end.output_enabled = true;
 | 
					 | 
				
			||||||
		force_output_enabled = true;
 | 
					 | 
				
			||||||
		/* Fill in the peer address so that we can send Init-ACK back: */
 | 
					 | 
				
			||||||
		prev_rem_addr = conn_rtp_src->end.addr;
 | 
					 | 
				
			||||||
		prev_rem_rtp_port = osmo_sockaddr_port(&conn_rtp_src->end.addr.u.sa);
 | 
					 | 
				
			||||||
		conn_rtp_src->end.addr = *mc->from_addr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = _conn_iuup_rtp_pl_up(conn_rtp_src, msg);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (force_output_enabled) {
 | 
					 | 
				
			||||||
		conn_rtp_src->end.output_enabled = prev_output_enabled;
 | 
					 | 
				
			||||||
		conn_rtp_src->end.addr = prev_rem_addr;
 | 
					 | 
				
			||||||
		osmo_sockaddr_set_port(&conn_rtp_src->end.addr.u.sa, prev_rem_rtp_port);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
free_ret:
 | 
					 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Build IuUP RNL Data primitive from msg containing an incoming RTP pkt from
 | 
					 | 
				
			||||||
 * peer and send it down the IuUP layer towards the destination as IuUP/RTP: */
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn_rtp *conn_dest_rtp, struct msgb *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp;
 | 
					 | 
				
			||||||
	struct rtp_hdr *rtph;
 | 
					 | 
				
			||||||
	int rc = -1;
 | 
					 | 
				
			||||||
	int iuup_length = 0;
 | 
					 | 
				
			||||||
	int8_t rfci;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Tx RNL-DATA.req */
 | 
					 | 
				
			||||||
	rtph = (struct rtp_hdr *)msgb_data(msg);
 | 
					 | 
				
			||||||
	msgb_pull(msg, sizeof(*rtph));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* FIXME: validate amr packets */
 | 
					 | 
				
			||||||
	irp = osmo_iuup_rnl_prim_alloc(conn_dest_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
					 | 
				
			||||||
	irp->u.data.frame_nr = htons(rtph->sequence) % 16;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* TODO: CMR handling & multiple frames handling */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR,
 | 
					 | 
				
			||||||
			     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n",
 | 
					 | 
				
			||||||
			     conn_src_rtp->end.codec->subtype_name);
 | 
					 | 
				
			||||||
		goto free_ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) {
 | 
					 | 
				
			||||||
		struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg);
 | 
					 | 
				
			||||||
		if (msgb_length(msg) < (sizeof(*amr_hdr))) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Bridge RTP=>IuUP: too short for AMR OA hdr (%u)\n", msgb_length(msg));
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!osmo_amr_ft_valid(amr_hdr->ft)) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR OA ft=%u\n", amr_hdr->ft);
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if ((rfci =  _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, amr_hdr->ft)) < 0) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR OA ft=%u\n", amr_hdr->ft);
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		irp->u.data.fqc = amr_hdr->q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
					 | 
				
			||||||
		irp->u.data.rfci = rfci;
 | 
					 | 
				
			||||||
		msgb_pull(msg, 2);
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR OA -> IuUP: ft %d -> rfci %d len %d\n",
 | 
					 | 
				
			||||||
		     amr_hdr->ft, rfci, msgb_length(msg));
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		uint8_t *amr_bwe_hdr = (uint8_t *) msgb_data(msg);
 | 
					 | 
				
			||||||
		int8_t ft;
 | 
					 | 
				
			||||||
		uint8_t q;
 | 
					 | 
				
			||||||
		if (msgb_length(msg) < 2) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "Bridge RTP=>IuUP: too short for AMR BE hdr (%u)\n", msgb_length(msg));
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ft = ((amr_bwe_hdr[0] & 0x07) << 1) | ((amr_bwe_hdr[1] & 0x80) >> 7);
 | 
					 | 
				
			||||||
		if (!osmo_amr_ft_valid(ft)) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: wrong AMR BE ft=%u\n", ft);
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if ((rfci =  _conn_iuup_amr_ft_2_rfci(conn_dest_rtp, ft)) < 0) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_dest_rtp, LOGL_NOTICE, "Bridge RTP=>IuUP: No RFCI found for AMR BE ft=%u\n", ft);
 | 
					 | 
				
			||||||
			goto free_ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		q = amr_bwe_hdr[1] & 0x40;
 | 
					 | 
				
			||||||
		irp->u.data.fqc = q ? IUUP_FQC_FRAME_GOOD : IUUP_FQC_FRAME_BAD;
 | 
					 | 
				
			||||||
		irp->u.data.rfci = rfci;
 | 
					 | 
				
			||||||
		rc = iuup_length = osmo_amr_bwe_to_iuup(msgb_data(msg), msgb_length(msg));
 | 
					 | 
				
			||||||
		if (rc < 0) {
 | 
					 | 
				
			||||||
			LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed convert the RTP/AMR to IuUP payload\n");
 | 
					 | 
				
			||||||
			return rc;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		msgb_trim(msg, iuup_length);
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_DEBUG, "Convert AMR BE -> IuUP: ft %d -> rfci %d len %d\n",
 | 
					 | 
				
			||||||
		     ft, rfci, msgb_length(msg));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	irp->oph.msg->l3h = msgb_put(irp->oph.msg, msgb_length(msg));
 | 
					 | 
				
			||||||
	memcpy(irp->oph.msg->l3h, msgb_data(msg), msgb_length(msg));
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_rnl_prim_down(conn_dest_rtp->iuup.iui, irp)) != 0)
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_dest_rtp, LOGL_ERROR, "Bridge RTP=>IuUP: Failed Tx RTP payload down the IuUP layer\n");
 | 
					 | 
				
			||||||
	return rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
free_ret:
 | 
					 | 
				
			||||||
	msgb_free(irp->oph.msg);
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Build IuUP RNL Data primitive from msg containing dummy content and send it
 | 
					 | 
				
			||||||
 * down the IuUP layer towards the destination as IuUP/RTP: */
 | 
					 | 
				
			||||||
int mgcp_conn_iuup_send_dummy(struct mgcp_conn_rtp *conn_rtp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct osmo_iuup_rnl_prim *irp;
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (conn_rtp->iuup.rfci_id_no_data == -1) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_NOTICE, "No RFCI NO_DATA found, unable to send dummy packet\n");
 | 
					 | 
				
			||||||
		return -ENOTSUP;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	irp = osmo_iuup_rnl_prim_alloc(conn_rtp->conn, OSMO_IUUP_RNL_DATA, PRIM_OP_REQUEST, MGW_IUUP_MSGB_SIZE);
 | 
					 | 
				
			||||||
	irp->u.data.frame_nr = 0;
 | 
					 | 
				
			||||||
	irp->u.data.fqc = IUUP_FQC_FRAME_GOOD;
 | 
					 | 
				
			||||||
	irp->u.data.rfci = conn_rtp->iuup.rfci_id_no_data;
 | 
					 | 
				
			||||||
	irp->oph.msg->l3h = irp->oph.msg->tail;
 | 
					 | 
				
			||||||
	if ((rc = osmo_iuup_rnl_prim_down(conn_rtp->iuup.iui, irp)) != 0) {
 | 
					 | 
				
			||||||
		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "Failed Tx RTP dummy payload down the IuUP layer\n");
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -110,7 +110,8 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Special handling for RTP connections */
 | 
						/* Special handling for RTP connections */
 | 
				
			||||||
	if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
						if (conn->type == MGCP_CONN_TYPE_RTP) {
 | 
				
			||||||
		conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY);
 | 
							conn->u.rtp.end.output_enabled =
 | 
				
			||||||
 | 
							    conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn));
 | 
				
			||||||
@@ -120,7 +121,7 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* 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) {
 | 
				
			||||||
		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n",
 | 
							LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
 | 
				
			||||||
			 conn->u.rtp.end.output_enabled);
 | 
								 conn->u.rtp.end.output_enabled);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,7 +203,7 @@ int mgcp_parse_osmux_cid(const char *line)
 | 
				
			|||||||
		     osmux_cid, OSMUX_CID_MAX);
 | 
							     osmux_cid, OSMUX_CID_MAX);
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid);
 | 
						LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return osmux_cid;
 | 
						return osmux_cid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,16 +48,21 @@
 | 
				
			|||||||
#include <osmocom/mgcp/debug.h>
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
#include <osmocom/codec/codec.h>
 | 
					#include <osmocom/codec/codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_e1.h>
 | 
					#include <osmocom/mgcp/mgcp_e1.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_iuup.h>
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RTP_SEQ_MOD		(1 << 16)
 | 
					#define RTP_SEQ_MOD		(1 << 16)
 | 
				
			||||||
#define RTP_MAX_DROPOUT		3000
 | 
					#define RTP_MAX_DROPOUT		3000
 | 
				
			||||||
#define RTP_MAX_MISORDER	100
 | 
					#define RTP_MAX_MISORDER	100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
					enum rtp_proto {
 | 
				
			||||||
 | 
						MGCP_PROTO_RTP,
 | 
				
			||||||
 | 
						MGCP_PROTO_RTCP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 | 
				
			||||||
				 int id, int inc)
 | 
									 int id, int inc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rate_ctr_group *conn_stats = conn_rtp->ctrg;
 | 
						struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
 | 
				
			||||||
	struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
						struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add to both the per-connection and the global stats */
 | 
						/* add to both the per-connection and the global stats */
 | 
				
			||||||
@@ -65,68 +70,49 @@ void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *
 | 
				
			|||||||
	rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
 | 
					static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
						rtpconn_rate_ctr_add(conn_rtp, endp, id, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rx_rtp(struct msgb *msg);
 | 
					static int rx_rtp(struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool addr_is_any(const struct osmo_sockaddr *osa)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (osa->u.sa.sa_family == AF_INET6) {
 | 
				
			||||||
 | 
							struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
 | 
				
			||||||
 | 
							return memcmp(&osa->u.sin6.sin6_addr,
 | 
				
			||||||
 | 
									   &ip6_any, sizeof(ip6_any)) == 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return osa->u.sin.sin_addr.s_addr == 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
					bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) &&
 | 
						return rtp_end->rtp_port && !addr_is_any(&rtp_end->addr);
 | 
				
			||||||
	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Determine the local rtp bind IP-address.
 | 
					/*! Determine the local rtp bind IP-address.
 | 
				
			||||||
 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
					 *  \param[out] addr caller provided memory to store the resulting IP-Address.
 | 
				
			||||||
 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
					 *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters.
 | 
				
			||||||
 * \ returns 0 on success, -1 if no local address could be provided.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  The local bind IP-address is automatically selected by probing the
 | 
					 *  The local bind IP-address is automatically selected by probing the
 | 
				
			||||||
 *  IP-Address of the interface that is pointing towards the remote IP-Address,
 | 
					 *  IP-Address of the interface that is pointing towards the remote IP-Address,
 | 
				
			||||||
 *  if no remote IP-Address is known yet, the statically configured
 | 
					 *  if no remote IP-Address is known yet, the statically configured
 | 
				
			||||||
 *  IP-Addresses are used as fallback. */
 | 
					 *  IP-Addresses are used as fallback. */
 | 
				
			||||||
int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
					void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct mgcp_endpoint *endp = conn->conn->endp;
 | 
					
 | 
				
			||||||
	const struct mgcp_config *cfg = endp->trunk->cfg;
 | 
						struct mgcp_endpoint *endp;
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	bool rem_addr_set = osmo_sockaddr_is_any(&conn->end.addr) == 0;
 | 
						endp = conn->conn->endp;
 | 
				
			||||||
	const char *bind_addr;
 | 
						bool rem_addr_set = !addr_is_any(&conn->end.addr);
 | 
				
			||||||
 | 
						char *bind_addr;
 | 
				
			||||||
	/* Osmux: No smart IP addresses allocation is supported yet. Simply
 | 
					 | 
				
			||||||
	 * return the one set in VTY config: */
 | 
					 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
					 | 
				
			||||||
		if (rem_addr_set) {
 | 
					 | 
				
			||||||
			/* Match IP version with what was requested from remote: */
 | 
					 | 
				
			||||||
			bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
					 | 
				
			||||||
				    cfg->osmux.local_addr_v6 :
 | 
					 | 
				
			||||||
				    cfg->osmux.local_addr_v4;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			/* Choose any of the bind addresses, preferring v6 over v4 if available: */
 | 
					 | 
				
			||||||
			bind_addr = cfg->osmux.local_addr_v6;
 | 
					 | 
				
			||||||
			if (!bind_addr)
 | 
					 | 
				
			||||||
				bind_addr = cfg->osmux.local_addr_v4;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!bind_addr) {
 | 
					 | 
				
			||||||
			LOGPCONN(conn->conn, DOSMUX, LOGL_ERROR,
 | 
					 | 
				
			||||||
				"Unable to locate local Osmux address, check your configuration! v4=%u v6=%u remote_known=%s\n",
 | 
					 | 
				
			||||||
				!!cfg->osmux.local_addr_v4,
 | 
					 | 
				
			||||||
				!!cfg->osmux.local_addr_v6,
 | 
					 | 
				
			||||||
				rem_addr_set ? osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf) : "no");
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		LOGPCONN(conn->conn, DOSMUX, LOGL_DEBUG,
 | 
					 | 
				
			||||||
			 "Using configured osmux bind ip as local bind ip %s\n",
 | 
					 | 
				
			||||||
			 bind_addr);
 | 
					 | 
				
			||||||
		osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Try probing the local IP-Address */
 | 
						/* Try probing the local IP-Address */
 | 
				
			||||||
	if (cfg->net_ports.bind_addr_probe && rem_addr_set) {
 | 
						if (endp->trunk->cfg->net_ports.bind_addr_probe && rem_addr_set) {
 | 
				
			||||||
		rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
							rc = osmo_sock_local_ip(addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
@@ -135,22 +121,22 @@ int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
			LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
								LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
				 "selected local rtp bind ip %s by probing using remote ip %s\n",
 | 
									 "selected local rtp bind ip %s by probing using remote ip %s\n",
 | 
				
			||||||
				 addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
									 addr, osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf));
 | 
				
			||||||
			return 0;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Select from preconfigured IP-Addresses. */
 | 
						/* Select from preconfigured IP-Addresses. We don't have bind_addr for Osmux (yet?). */
 | 
				
			||||||
	if (rem_addr_set) {
 | 
						if (rem_addr_set) {
 | 
				
			||||||
		/* Check there is a bind IP for the RTP traffic configured,
 | 
							/* Check there is a bind IP for the RTP traffic configured,
 | 
				
			||||||
		 * if so, use that IP-Address */
 | 
							 * if so, use that IP-Address */
 | 
				
			||||||
		bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
							bind_addr = conn->end.addr.u.sa.sa_family == AF_INET6 ?
 | 
				
			||||||
				cfg->net_ports.bind_addr_v6 :
 | 
									endp->trunk->cfg->net_ports.bind_addr_v6 :
 | 
				
			||||||
				cfg->net_ports.bind_addr_v4;
 | 
									endp->trunk->cfg->net_ports.bind_addr_v4;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Choose any of the bind addresses, preferring v6 over v4 */
 | 
							/* Choose any of the bind addresses, preferring v6 over v4 */
 | 
				
			||||||
		bind_addr = cfg->net_ports.bind_addr_v6;
 | 
							bind_addr = endp->trunk->cfg->net_ports.bind_addr_v6;
 | 
				
			||||||
		if (!strlen(bind_addr))
 | 
							if (!strlen(bind_addr))
 | 
				
			||||||
			bind_addr = cfg->net_ports.bind_addr_v4;
 | 
								bind_addr = endp->trunk->cfg->net_ports.bind_addr_v4;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strlen(bind_addr)) {
 | 
						if (strlen(bind_addr)) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
@@ -160,18 +146,17 @@ int mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		/* No specific bind IP is configured for the RTP traffic, so
 | 
							/* No specific bind IP is configured for the RTP traffic, so
 | 
				
			||||||
		 * assume the IP where we listen for incoming MGCP messages
 | 
							 * assume the IP where we listen for incoming MGCP messages
 | 
				
			||||||
		 * as bind IP */
 | 
							 * as bind IP */
 | 
				
			||||||
		bind_addr = cfg->source_addr;
 | 
							bind_addr = endp->trunk->cfg->source_addr;
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
 | 
								"using mgcp bind ip as local rtp bind ip: %s\n", bind_addr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
						osmo_strlcpy(addr, bind_addr, INET6_ADDRSTRLEN);
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This does not need to be a precision timestamp and
 | 
					/* This does not need to be a precision timestamp and
 | 
				
			||||||
 * is allowed to wrap quite fast. The returned value is
 | 
					 * is allowed to wrap quite fast. The returned value is
 | 
				
			||||||
 * 1/codec_rate seconds. */
 | 
					 * 1/codec_rate seconds. */
 | 
				
			||||||
uint32_t mgcp_get_current_ts(unsigned codec_rate)
 | 
					static uint32_t get_current_ts(unsigned codec_rate)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct timespec tp;
 | 
						struct timespec tp;
 | 
				
			||||||
	uint64_t ret;
 | 
						uint64_t ret;
 | 
				
			||||||
@@ -544,7 +529,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
	seq = ntohs(rtp_hdr->sequence);
 | 
						seq = ntohs(rtp_hdr->sequence);
 | 
				
			||||||
	timestamp = ntohl(rtp_hdr->timestamp);
 | 
						timestamp = ntohl(rtp_hdr->timestamp);
 | 
				
			||||||
	arrival_time = mgcp_get_current_ts(rtp_end->codec->rate);
 | 
						arrival_time = get_current_ts(rtp_end->codec->rate);
 | 
				
			||||||
	ssrc = ntohl(rtp_hdr->ssrc);
 | 
						ssrc = ntohl(rtp_hdr->ssrc);
 | 
				
			||||||
	marker_bit = !!rtp_hdr->marker;
 | 
						marker_bit = !!rtp_hdr->marker;
 | 
				
			||||||
	transit = arrival_time - timestamp;
 | 
						transit = arrival_time - timestamp;
 | 
				
			||||||
@@ -691,7 +676,7 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "RTP packet too short (%d < %zu)\n",
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n",
 | 
				
			||||||
			 msgb_length(msg), sizeof(struct rtp_hdr));
 | 
								 msgb_length(msg), sizeof(struct rtp_hdr));
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -717,18 +702,11 @@ static int rfc5993_hr_convert(struct mgcp_endpoint *endp, struct msgb *msg)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Convert msg to AMR RTP framing mode specified by target_is_oa.
 | 
					/* For AMR RTP two framing modes are defined RFC3267. There is a bandwith
 | 
				
			||||||
 *  \param[in] endp MGCP Endpoint where this message belongs to (used for logging purposes)
 | 
					 | 
				
			||||||
 *  \param[in] msg Message containing an AMR RTP payload (in octet-aligned or bandwidth-efficient format).
 | 
					 | 
				
			||||||
 *  \param[in] target_is_oa the target framing mode that msg will contain after this function succeeds.
 | 
					 | 
				
			||||||
 *  \returns The size of the new RTP AMR content on success, negative on error.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * For AMR RTP two framing modes are defined RFC3267. There is a bandwidth
 | 
					 | 
				
			||||||
 * efficient encoding scheme where all fields are packed together one after
 | 
					 * efficient encoding scheme where all fields are packed together one after
 | 
				
			||||||
 * another and an octet aligned mode where all fields are aligned to octet
 | 
					 * another and an octet aligned mode where all fields are aligned to octet
 | 
				
			||||||
 * boundaries. This function is used to convert between the two modes.
 | 
					 * boundaries. This function is used to convert between the two modes */
 | 
				
			||||||
 */
 | 
					static int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			||||||
int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
					 | 
				
			||||||
			      bool target_is_oa)
 | 
								      bool target_is_oa)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
 | 
						/* NOTE: the msgb has an allocated length of RTP_BUF_SIZE, so there is
 | 
				
			||||||
@@ -737,7 +715,6 @@ int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	struct rtp_hdr *rtp_hdr;
 | 
						struct rtp_hdr *rtp_hdr;
 | 
				
			||||||
	unsigned int payload_len;
 | 
						unsigned int payload_len;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	bool orig_is_oa;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
						if (msgb_length(msg) < sizeof(struct rtp_hdr)) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR, "AMR RTP packet too short (%d < %zu)\n", msgb_length(msg), sizeof(struct rtp_hdr));
 | 
				
			||||||
@@ -745,10 +722,10 @@ int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
						rtp_hdr = (struct rtp_hdr *)msgb_data(msg);
 | 
				
			||||||
	payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
 | 
					 | 
				
			||||||
	orig_is_oa = osmo_amr_is_oa(rtp_hdr->data, payload_len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (orig_is_oa) {
 | 
						payload_len = msgb_length(msg) - sizeof(struct rtp_hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmo_amr_is_oa(rtp_hdr->data, payload_len)) {
 | 
				
			||||||
		if (!target_is_oa)
 | 
							if (!target_is_oa)
 | 
				
			||||||
			/* Input data is oa an target format is bwe
 | 
								/* Input data is oa an target format is bwe
 | 
				
			||||||
			 * ==> convert */
 | 
								 * ==> convert */
 | 
				
			||||||
@@ -770,16 +747,27 @@ int amr_oa_bwe_convert(struct mgcp_endpoint *endp, struct msgb *msg,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "RTP AMR packet conversion %s->%s failed: %s\n",
 | 
								 "AMR RTP packet conversion failed\n");
 | 
				
			||||||
			 orig_is_oa ? "OA" : "BWE",
 | 
					 | 
				
			||||||
			 target_is_oa ? "OA" : "BWE",
 | 
					 | 
				
			||||||
			 osmo_hexdump(rtp_hdr->data, payload_len));
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
 | 
						return msgb_trim(msg, rc + sizeof(struct rtp_hdr));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Check if a conversion between octet-aligned and bandwith-efficient mode is
 | 
				
			||||||
 | 
					 * indicated. */
 | 
				
			||||||
 | 
					static bool amr_oa_bwe_convert_indicated(struct mgcp_rtp_codec *codec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (codec->param_present == false)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (!codec->param.amr_octet_aligned_present)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						if (strcmp(codec->subtype_name, "AMR") != 0)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
 | 
					/* Return whether an RTP packet with AMR payload is in octet-aligned mode.
 | 
				
			||||||
 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
 | 
					 * Return 0 if in bandwidth-efficient mode, 1 for octet-aligned mode, and negative if the RTP data is invalid. */
 | 
				
			||||||
static int amr_oa_check(char *data, int len)
 | 
					static int amr_oa_check(char *data, int len)
 | 
				
			||||||
@@ -801,7 +789,7 @@ static int amr_oa_check(char *data, int len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Forward data to a debug tap. This is debug function that is intended for
 | 
					/* Forward data to a debug tap. This is debug function that is intended for
 | 
				
			||||||
 * debugging the voice traffic with tools like gstreamer */
 | 
					 * debugging the voice traffic with tools like gstreamer */
 | 
				
			||||||
void forward_data_tap(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
 | 
					static void forward_data(int fd, struct mgcp_rtp_tap *tap, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -827,7 +815,7 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	hdr->version = 2;
 | 
						hdr->version = 2;
 | 
				
			||||||
	hdr->payload_type = rtp_end->codec->payload_type;
 | 
						hdr->payload_type = rtp_end->codec->payload_type;
 | 
				
			||||||
	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate));
 | 
						hdr->timestamp = osmo_htonl(get_current_ts(rtp_end->codec->rate));
 | 
				
			||||||
	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
 | 
						hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
 | 
				
			||||||
	hdr->ssrc = state->alt_rtp_tx_ssrc;
 | 
						hdr->ssrc = state->alt_rtp_tx_ssrc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -838,7 +826,7 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (osmo_sockaddr_is_any(&conn->end.addr) != 0) {
 | 
						if (addr_is_any(&conn->end.addr)) {
 | 
				
			||||||
		switch (conn->conn->mode) {
 | 
							switch (conn->conn->mode) {
 | 
				
			||||||
		case MGCP_CONN_LOOPBACK:
 | 
							case MGCP_CONN_LOOPBACK:
 | 
				
			||||||
			/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
 | 
								/* HACK: for IuUP, we want to reply with an IuUP Initialization ACK upon the first RTP
 | 
				
			||||||
@@ -887,14 +875,14 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
	 * the same as the remote port where we transmit outgoing RTP traffic
 | 
						 * the same as the remote port where we transmit outgoing RTP traffic
 | 
				
			||||||
	 * to (set by MDCX). We use this to check the origin of the data for
 | 
						 * to (set by MDCX). We use this to check the origin of the data for
 | 
				
			||||||
	 * plausibility. */
 | 
						 * plausibility. */
 | 
				
			||||||
	if (osmo_sockaddr_port(&conn->end.addr.u.sa) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
						if (ntohs(conn->end.rtp_port) != osmo_sockaddr_port(&addr->u.sa) &&
 | 
				
			||||||
	    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
						    ntohs(conn->end.rtcp_port) != osmo_sockaddr_port(&addr->u.sa)) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "data from wrong source port: %d, ",
 | 
								 "data from wrong source port: %d, ",
 | 
				
			||||||
			 osmo_sockaddr_port(&addr->u.sa));
 | 
								 osmo_sockaddr_port(&addr->u.sa));
 | 
				
			||||||
		LOGPC(DRTP, LOGL_ERROR,
 | 
							LOGPC(DRTP, LOGL_ERROR,
 | 
				
			||||||
		      "expected: %d for RTP or %d for RTCP\n",
 | 
							      "expected: %d for RTP or %d for RTCP\n",
 | 
				
			||||||
		      osmo_sockaddr_port(&conn->end.addr.u.sa), ntohs(conn->end.rtcp_port));
 | 
							      ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR, "packet tossed\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -907,29 +895,28 @@ static int check_rtp_origin(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *ad
 | 
				
			|||||||
static int check_rtp_destin(struct mgcp_conn_rtp *conn)
 | 
					static int check_rtp_destin(struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	bool ip_is_any = osmo_sockaddr_is_any(&conn->end.addr) != 0;
 | 
						bool ip_is_any = addr_is_any(&conn->end.addr);
 | 
				
			||||||
	uint16_t port = osmo_sockaddr_port(&conn->end.addr.u.sa);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Note: it is legal to create a connection but never setting a port
 | 
						/* Note: it is legal to create a connection but never setting a port
 | 
				
			||||||
	 * and IP-address for outgoing data. */
 | 
						 * and IP-address for outgoing data. */
 | 
				
			||||||
	if (ip_is_any && port == 0) {
 | 
						if (ip_is_any && conn->end.rtp_port == 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "destination IP-address and rtp port is not (yet) known (%s:%u)\n",
 | 
								 "destination IP-address and rtp port is not (yet) known (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ip_is_any) {
 | 
						if (ip_is_any) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "destination IP-address is invalid (%s:%u)\n",
 | 
								 "destination IP-address is invalid (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port == 0) {
 | 
						if (conn->end.rtp_port == 0) {
 | 
				
			||||||
		LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
							LOGPCONN(conn->conn, DRTP, LOGL_ERROR,
 | 
				
			||||||
			 "destination rtp port is invalid (%s:%u)\n",
 | 
								 "destination rtp port is invalid (%s:%u)\n",
 | 
				
			||||||
			 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), port);
 | 
								 osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf), conn->end.rtp_port);
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -988,21 +975,14 @@ static int check_rtp(struct mgcp_conn_rtp *conn_src, struct msgb *msg)
 | 
				
			|||||||
	 * the length is because we currently handle IUUP packets as RTP
 | 
						 * the length is because we currently handle IUUP packets as RTP
 | 
				
			||||||
	 * packets, so they must pass this check, if we weould be more
 | 
						 * packets, so they must pass this check, if we weould be more
 | 
				
			||||||
	 * strict here, we would possibly break 3G. (see also FIXME note
 | 
						 * strict here, we would possibly break 3G. (see also FIXME note
 | 
				
			||||||
	 * below.*/
 | 
						 * below */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dispatch msg bridged from the sister conn in the endpoint.
 | 
					/* Send RTP data. Possible options are standard RTP packet
 | 
				
			||||||
 *  \param[in] conn_dst The destination conn that should handle and transmit the content to
 | 
					 * transmission or trsmission via an osmux connection */
 | 
				
			||||||
 *			its peer outside MGW.
 | 
					static int mgcp_send_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
				
			||||||
 *  \param[in] msg msgb containing an RTP pkt received by the sister conn in the endpoint,
 | 
					 | 
				
			||||||
 *  \returns bytes sent, -1 on error.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Possible options are standard RTP packet transmission, transmission
 | 
					 | 
				
			||||||
 * via IuUP or transmission via an osmux connection.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msgb *msg)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
	enum rtp_proto proto = mc->proto;
 | 
						enum rtp_proto proto = mc->proto;
 | 
				
			||||||
@@ -1027,24 +1007,12 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
 | 
				
			|||||||
			 "using mgcp_send() to forward data directly\n");
 | 
								 "using mgcp_send() to forward data directly\n");
 | 
				
			||||||
		return mgcp_send(endp, proto == MGCP_PROTO_RTP,
 | 
							return mgcp_send(endp, proto == MGCP_PROTO_RTP,
 | 
				
			||||||
				 mc->from_addr, msg, conn_src, conn_dst);
 | 
									 mc->from_addr, msg, conn_src, conn_dst);
 | 
				
			||||||
	case MGCP_RTP_OSMUX:
 | 
						case MGCP_OSMUX_BSC_NAT:
 | 
				
			||||||
 | 
						case MGCP_OSMUX_BSC:
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "endpoint type is MGCP_RTP_OSMUX, "
 | 
								 "endpoint type is MGCP_OSMUX_BSC_NAT, "
 | 
				
			||||||
			 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
 | 
								 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n");
 | 
				
			||||||
		return conn_osmux_send_rtp(conn_dst, msg);
 | 
							return osmux_xfrm_to_osmux((char*)msgb_data(msg), msgb_length(msg), conn_dst);
 | 
				
			||||||
	case MGCP_RTP_IUUP:
 | 
					 | 
				
			||||||
		if (proto == MGCP_PROTO_RTP) {
 | 
					 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
				 "endpoint type is MGCP_RTP_IUUP, "
 | 
					 | 
				
			||||||
				 "using mgcp_conn_iuup_send_rtp() to forward data over IuUP\n");
 | 
					 | 
				
			||||||
			return mgcp_conn_iuup_send_rtp(conn_src, conn_dst, msg);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* RTCP: we forward as usual for regular RTP connection */
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
					 | 
				
			||||||
			 "endpoint type is MGCP_RTP_IUUP and proto!=MGCP_PROTO_RTP, "
 | 
					 | 
				
			||||||
			 "using mgcp_send() to forward data directly\n");
 | 
					 | 
				
			||||||
		return mgcp_send(endp, false,
 | 
					 | 
				
			||||||
				 mc->from_addr, msg, conn_src, conn_dst);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the data has not been handled/forwarded until here, it will
 | 
						/* If the data has not been handled/forwarded until here, it will
 | 
				
			||||||
@@ -1058,22 +1026,26 @@ static int mgcp_conn_rtp_dispatch_rtp(struct mgcp_conn_rtp *conn_dst, struct msg
 | 
				
			|||||||
/*! send udp packet.
 | 
					/*! send udp packet.
 | 
				
			||||||
 *  \param[in] fd associated file descriptor.
 | 
					 *  \param[in] fd associated file descriptor.
 | 
				
			||||||
 *  \param[in] addr destination ip-address.
 | 
					 *  \param[in] addr destination ip-address.
 | 
				
			||||||
 | 
					 *  \param[in] port destination UDP port (network byte order).
 | 
				
			||||||
 *  \param[in] buf buffer that holds the data to be send.
 | 
					 *  \param[in] buf buffer that holds the data to be send.
 | 
				
			||||||
 *  \param[in] len length of the data to be sent.
 | 
					 *  \param[in] len length of the data to be sent.
 | 
				
			||||||
 *  \returns bytes sent, -1 on error. */
 | 
					 *  \returns bytes sent, -1 on error. */
 | 
				
			||||||
int mgcp_udp_send(int fd, const struct osmo_sockaddr *addr, const char *buf, int len)
 | 
					int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char ipbuf[INET6_ADDRSTRLEN];
 | 
						char ipbuf[INET6_ADDRSTRLEN];
 | 
				
			||||||
	size_t addr_len;
 | 
						size_t addr_len;
 | 
				
			||||||
 | 
						bool is_ipv6 =  addr->u.sa.sa_family == AF_INET6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRTP, LOGL_DEBUG,
 | 
						LOGP(DRTP, LOGL_DEBUG,
 | 
				
			||||||
	     "sending %i bytes length packet to %s:%u ...\n", len,
 | 
						     "sending %i bytes length packet to %s:%u ...\n", len,
 | 
				
			||||||
	     osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
						     osmo_sockaddr_ntop(&addr->u.sa, ipbuf),
 | 
				
			||||||
	     osmo_sockaddr_port(&addr->u.sa));
 | 
						     ntohs(port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (addr->u.sa.sa_family == AF_INET6) {
 | 
						if (is_ipv6) {
 | 
				
			||||||
 | 
							addr->u.sin6.sin6_port = port;
 | 
				
			||||||
		addr_len = sizeof(addr->u.sin6);
 | 
							addr_len = sizeof(addr->u.sin6);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							addr->u.sin.sin_port = port;
 | 
				
			||||||
		addr_len = sizeof(addr->u.sin);
 | 
							addr_len = sizeof(addr->u.sin);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1088,7 +1060,6 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	int was_rtcp = 0;
 | 
						int was_rtcp = 0;
 | 
				
			||||||
	struct osmo_sockaddr rtcp_addr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
@@ -1102,11 +1073,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	if (check_rtp_destin(conn) != 0)
 | 
						if (check_rtp_destin(conn) != 0)
 | 
				
			||||||
		goto failed;
 | 
							goto failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_conn_rtp_is_iuup(conn))
 | 
					 | 
				
			||||||
		rc = mgcp_conn_iuup_send_dummy(conn);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
 | 
						rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
 | 
				
			||||||
				   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
								   conn->end.rtp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc == -1)
 | 
						if (rc == -1)
 | 
				
			||||||
		goto failed;
 | 
							goto failed;
 | 
				
			||||||
@@ -1115,10 +1083,8 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	was_rtcp = 1;
 | 
						was_rtcp = 1;
 | 
				
			||||||
	rtcp_addr = conn->end.addr;
 | 
						rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
 | 
				
			||||||
	osmo_sockaddr_set_port(&rtcp_addr.u.sa, ntohs(conn->end.rtcp_port));
 | 
								   conn->end.rtcp_port, rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
				
			||||||
	rc = mgcp_udp_send(conn->end.rtcp.fd, &rtcp_addr,
 | 
					 | 
				
			||||||
			   rtp_dummy_payload, sizeof(rtp_dummy_payload));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rc >= 0)
 | 
						if (rc >= 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
@@ -1164,13 +1130,6 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG, "delivering RTCP packet...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Patch the payload type number: translate from conn_src to conn_dst.
 | 
					 | 
				
			||||||
	 * Do not patch for IuUP, where the correct payload type number is already set in bridge_iuup_to_rtp_peer():
 | 
					 | 
				
			||||||
	 * IuUP -> AMR: calls this function, skip patching if conn_src is IuUP.
 | 
					 | 
				
			||||||
	 * {AMR or IuUP} -> IuUP: calls mgcp_udp_send() directly, skipping this function: No need to examine dst. */
 | 
					 | 
				
			||||||
	if (is_rtp && !mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
					 | 
				
			||||||
		rc = mgcp_patch_pt(conn_src, conn_dst, msg);
 | 
					 | 
				
			||||||
		if (rc < 0) {
 | 
					 | 
				
			||||||
	/* FIXME: It is legal that the payload type on the egress connection is
 | 
						/* FIXME: It is legal that the payload type on the egress connection is
 | 
				
			||||||
	 * different from the payload type that has been negotiated on the
 | 
						 * different from the payload type that has been negotiated on the
 | 
				
			||||||
	 * ingress connection. Essentially the codecs are the same so we can
 | 
						 * ingress connection. Essentially the codecs are the same so we can
 | 
				
			||||||
@@ -1179,6 +1138,9 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	 * course unable to patch the payload type. A situation like this
 | 
						 * course unable to patch the payload type. A situation like this
 | 
				
			||||||
	 * should not occur if transcoding is consequently avoided. Until
 | 
						 * should not occur if transcoding is consequently avoided. Until
 | 
				
			||||||
	 * we have transcoding support in osmo-mgw we can not resolve this. */
 | 
						 * we have transcoding support in osmo-mgw we can not resolve this. */
 | 
				
			||||||
 | 
						if (is_rtp) {
 | 
				
			||||||
 | 
							rc = mgcp_patch_pt(conn_src, conn_dst, msg);
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
			LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
								LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
				 "can not patch PT because no suitable egress codec was found.\n");
 | 
									 "can not patch PT because no suitable egress codec was found.\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1202,7 +1164,7 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
			 "rtp_port:%u rtcp_port:%u\n",
 | 
								 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name,
 | 
								 dest_name,
 | 
				
			||||||
			 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
								 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
								 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
		    );
 | 
							    );
 | 
				
			||||||
	} else if (is_rtp) {
 | 
						} else if (is_rtp) {
 | 
				
			||||||
		int cont;
 | 
							int cont;
 | 
				
			||||||
@@ -1223,15 +1185,12 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
				mgcp_patch_and_count(endp, rtp_state, rtp_end,
 | 
									mgcp_patch_and_count(endp, rtp_state, rtp_end,
 | 
				
			||||||
						     addr, msg);
 | 
											     addr, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) {
 | 
								if (amr_oa_bwe_convert_indicated(conn_dst->end.codec)) {
 | 
				
			||||||
				/* the iuup code will correctly transform to the correct AMR mode */
 | 
					 | 
				
			||||||
			} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) {
 | 
					 | 
				
			||||||
				rc = amr_oa_bwe_convert(endp, msg,
 | 
									rc = amr_oa_bwe_convert(endp, msg,
 | 
				
			||||||
							conn_dst->end.codec->param.amr_octet_aligned);
 | 
												conn_dst->end.codec->param.amr_octet_aligned);
 | 
				
			||||||
				if (rc < 0) {
 | 
									if (rc < 0) {
 | 
				
			||||||
					LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
										LOGPENDP(endp, DRTP, LOGL_ERROR,
 | 
				
			||||||
						 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n",
 | 
											 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion\n");
 | 
				
			||||||
						 conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient");
 | 
					 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if (rtp_end->rfc5993_hr_convert &&
 | 
								} else if (rtp_end->rfc5993_hr_convert &&
 | 
				
			||||||
@@ -1248,14 +1207,32 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
				 "rtp_port:%u rtcp_port:%u\n",
 | 
									 "rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
				 dest_name,
 | 
									 dest_name,
 | 
				
			||||||
				 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
									 osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
				 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port)
 | 
									 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Forward a copy of the RTP data to a debug ip/port */
 | 
								/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
			forward_data_tap(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
								forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
 | 
				
			||||||
				     msg);
 | 
									     msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr,
 | 
								/* FIXME: HACK HACK HACK. See OS#2459.
 | 
				
			||||||
 | 
								 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
 | 
				
			||||||
 | 
								 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
 | 
				
			||||||
 | 
								 * cells (as long as we patch only the first RTP payload in each stream).
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!rtp_state->patched_first_rtp_payload
 | 
				
			||||||
 | 
								    && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
 | 
				
			||||||
 | 
									uint8_t *data = msgb_data(msg) + 12;
 | 
				
			||||||
 | 
									if (data[0] == 0xe0) {
 | 
				
			||||||
 | 
										data[0] = 0xe4;
 | 
				
			||||||
 | 
										data[1] = 0x00;
 | 
				
			||||||
 | 
										rtp_state->patched_first_rtp_payload = true;
 | 
				
			||||||
 | 
										LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
 | 
											 "Patching over first two bytes"
 | 
				
			||||||
 | 
											 " to fake an IuUP Initialization Ack\n");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								len = mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, rtp_end->rtp_port,
 | 
				
			||||||
					    (char *)msgb_data(msg), msgb_length(msg));
 | 
										    (char *)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (len <= 0)
 | 
								if (len <= 0)
 | 
				
			||||||
@@ -1270,17 +1247,15 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
		} while (buflen > 0);
 | 
							} while (buflen > 0);
 | 
				
			||||||
		return nbytes;
 | 
							return nbytes;
 | 
				
			||||||
	} else if (!trunk->omit_rtcp) {
 | 
						} else if (!trunk->omit_rtcp) {
 | 
				
			||||||
		struct osmo_sockaddr rtcp_addr = rtp_end->addr;
 | 
					 | 
				
			||||||
		osmo_sockaddr_set_port(&rtcp_addr.u.sa, rtp_end->rtcp_port);
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
							LOGPENDP(endp, DRTP, LOGL_DEBUG,
 | 
				
			||||||
			 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
								 "send to %s %s rtp_port:%u rtcp_port:%u\n",
 | 
				
			||||||
			 dest_name, osmo_sockaddr_ntop(&rtcp_addr.u.sa, ipbuf),
 | 
								 dest_name, osmo_sockaddr_ntop(&rtp_end->addr.u.sa, ipbuf),
 | 
				
			||||||
			 osmo_sockaddr_port(&rtp_end->addr.u.sa),
 | 
								 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
 | 
				
			||||||
			 osmo_sockaddr_port(&rtcp_addr.u.sa)
 | 
					 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		len = mgcp_udp_send(rtp_end->rtcp.fd, &rtcp_addr,
 | 
							len = mgcp_udp_send(rtp_end->rtcp.fd,
 | 
				
			||||||
				    (char *)msgb_data(msg), msgb_length(msg));
 | 
									    &rtp_end->addr,
 | 
				
			||||||
 | 
									    rtp_end->rtcp_port, (char *)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
							rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
		rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
							rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
 | 
				
			||||||
@@ -1292,12 +1267,13 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! Dispatch incoming RTP packet to opposite RTP connection.
 | 
					/*! dispatch incoming RTP packet to opposite RTP connection.
 | 
				
			||||||
 * \param[in] msg Message buffer to bridge, coming from source connection.
 | 
					 *  \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP).
 | 
				
			||||||
 *            msg shall contain "struct osmo_rtp_msg_ctx *" attached in
 | 
					 *  \param[in] addr socket address where the RTP packet has been received from.
 | 
				
			||||||
 *            "OSMO_RTP_MSG_CTX(msg)".
 | 
					 *  \param[in] buf buffer that hold the RTP payload.
 | 
				
			||||||
 *  \returns 0 on success, -1 on ERROR.
 | 
					 *  \param[in] buf_size size data length of buf.
 | 
				
			||||||
 */
 | 
					 *  \param[in] conn originating connection.
 | 
				
			||||||
 | 
					 *  \returns 0 on success, -1 on ERROR. */
 | 
				
			||||||
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
					int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
@@ -1315,9 +1291,6 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
	 *  destination connection is known the RTP packet is sent via
 | 
						 *  destination connection is known the RTP packet is sent via
 | 
				
			||||||
	 *  the destination connection. */
 | 
						 *  the destination connection. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If source is IuUP, we need to handle state, forward it through specific bridge path: */
 | 
					 | 
				
			||||||
	if (mgcp_conn_rtp_is_iuup(conn_src) && mc->proto == MGCP_PROTO_RTP)
 | 
					 | 
				
			||||||
		return mgcp_conn_iuup_dispatch_rtp(msg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	 /* Check if the connection is in loopback mode, if yes, just send the
 | 
						 /* Check if the connection is in loopback mode, if yes, just send the
 | 
				
			||||||
	 * incoming data back to the origin */
 | 
						 * incoming data back to the origin */
 | 
				
			||||||
@@ -1326,15 +1299,25 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
							if (conn->u.rtp.end.rtp_port == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn->u.rtp.end.addr));
 | 
				
			||||||
 | 
								switch (from_addr->u.sa.sa_family) {
 | 
				
			||||||
 | 
								case AF_INET:
 | 
				
			||||||
 | 
									conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case AF_INET6:
 | 
				
			||||||
 | 
									conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									OSMO_ASSERT(false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
									     conn->u.rtp.end.rtp_port);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							return mgcp_send_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find a destination connection. */
 | 
						/* Find a destination connection. */
 | 
				
			||||||
@@ -1366,7 +1349,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Dispatch RTP packet to destination RTP connection */
 | 
						/* Dispatch RTP packet to destination RTP connection */
 | 
				
			||||||
	return mgcp_conn_rtp_dispatch_rtp(&conn_dst->u.rtp, msg);
 | 
						return mgcp_send_rtp(&conn_dst->u.rtp, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
					/*! dispatch incoming RTP packet to E1 subslot, handle RTCP packets locally.
 | 
				
			||||||
@@ -1391,15 +1374,25 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg)
 | 
				
			|||||||
		 * packets back to their origin. We will use the originating
 | 
							 * packets back to their origin. We will use the originating
 | 
				
			||||||
		 * address data from the UDP packet header to patch the
 | 
							 * address data from the UDP packet header to patch the
 | 
				
			||||||
		 * outgoing address in connection on the fly */
 | 
							 * outgoing address in connection on the fly */
 | 
				
			||||||
		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) {
 | 
							if (conn->u.rtp.end.rtp_port == 0) {
 | 
				
			||||||
			memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
								memcpy(&conn->u.rtp.end.addr, from_addr,
 | 
				
			||||||
			       sizeof(conn->u.rtp.end.addr));
 | 
								       sizeof(conn->u.rtp.end.addr));
 | 
				
			||||||
 | 
								switch (from_addr->u.sa.sa_family) {
 | 
				
			||||||
 | 
								case AF_INET:
 | 
				
			||||||
 | 
									conn->u.rtp.end.rtp_port = from_addr->u.sin.sin_port;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case AF_INET6:
 | 
				
			||||||
 | 
									conn->u.rtp.end.rtp_port = from_addr->u.sin6.sin6_port;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									OSMO_ASSERT(false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
								LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
				
			||||||
				     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
									     "loopback mode: implicitly using source address (%s:%u) as destination address\n",
 | 
				
			||||||
				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
									     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf),
 | 
				
			||||||
				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa));
 | 
									     conn->u.rtp.end.rtp_port);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg);
 | 
							return mgcp_send_rtp(conn_src, msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward to E1 */
 | 
						/* Forward to E1 */
 | 
				
			||||||
@@ -1475,7 +1468,7 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
	msgb_put(msg, ret);
 | 
						msgb_put(msg, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
 | 
						LOG_CONN_RTP(conn_src, LOGL_DEBUG, "%s: rx %u bytes from %s:%u\n",
 | 
				
			||||||
		     proto == MGCP_PROTO_RTP ? "RTP" : "RTCP",
 | 
							     proto == MGCP_PROTO_RTP ? "RTP" : "RTPC",
 | 
				
			||||||
		     msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
 | 
							     msgb_length(msg), osmo_sockaddr_ntop(&addr.u.sa, ipbuf),
 | 
				
			||||||
		     osmo_sockaddr_port(&addr.u.sa));
 | 
							     osmo_sockaddr_port(&addr.u.sa));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1508,12 +1501,12 @@ static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
 | 
				
			|||||||
					sizeof(struct sockaddr_in)));
 | 
										sizeof(struct sockaddr_in)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Increment RX statistics */
 | 
						/* Increment RX statistics */
 | 
				
			||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_PACKETS_RX_CTR));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_PACKETS_RX_CTR));
 | 
				
			||||||
	rate_ctr_add(rate_ctr_group_get_ctr(conn_src->ctrg, RTP_OCTETS_RX_CTR), msgb_length(msg));
 | 
						rate_ctr_add(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_OCTETS_RX_CTR), msgb_length(msg));
 | 
				
			||||||
	/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
						/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Forward a copy of the RTP data to a debug ip/port */
 | 
						/* Forward a copy of the RTP data to a debug ip/port */
 | 
				
			||||||
	forward_data_tap(fd->fd, &conn_src->tap_in, msg);
 | 
						forward_data(fd->fd, &conn_src->tap_in, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = rx_rtp(msg);
 | 
						rc = rx_rtp(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1522,7 +1515,6 @@ out:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Note: This function is able to handle RTP and RTCP */
 | 
					 | 
				
			||||||
static int rx_rtp(struct msgb *msg)
 | 
					static int rx_rtp(struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
						struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 | 
				
			||||||
@@ -1533,29 +1525,23 @@ static int rx_rtp(struct msgb *msg)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
 | 
						LOG_CONN_RTP(conn_src, LOGL_DEBUG, "rx_rtp(%u bytes)\n", msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Check if the origin of the RTP packet seems plausible */
 | 
						mgcp_conn_watchdog_kick(conn_src->conn);
 | 
				
			||||||
	if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If AMR is configured for the ingress connection and conversion of the
 | 
						/* If AMR is configured for the ingress connection a conversion of the
 | 
				
			||||||
	 * framing mode (octet-aligned vs. bandwith-efficient) is explicitly
 | 
						 * framing mode (octet-aligned vs. bandwith-efficient is explicitly
 | 
				
			||||||
	 * defined, then we check if the incoming payload matches that
 | 
						 * define, then we check if the incoming payload matches that
 | 
				
			||||||
	 * expectation. */
 | 
						 * expectation. */
 | 
				
			||||||
	if (mc->proto == MGCP_PROTO_RTP &&
 | 
						if (amr_oa_bwe_convert_indicated(conn_src->end.codec)) {
 | 
				
			||||||
	    mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) {
 | 
					 | 
				
			||||||
		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
							int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg));
 | 
				
			||||||
		if (oa < 0)
 | 
							if (oa < 0)
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
		if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) {
 | 
							if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned)
 | 
				
			||||||
			LOG_CONN_RTP(conn_src, LOGL_NOTICE,
 | 
					 | 
				
			||||||
				     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u."
 | 
					 | 
				
			||||||
				     " check the config of your call-agent!\n",
 | 
					 | 
				
			||||||
				     msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa);
 | 
					 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_conn_watchdog_kick(conn_src->conn);
 | 
						/* Check if the origin of the RTP packet seems plausible */
 | 
				
			||||||
 | 
						if (!trunk->rtp_accept_all && check_rtp_origin(conn_src, from_addr))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Execute endpoint specific implementation that handles the
 | 
						/* Execute endpoint specific implementation that handles the
 | 
				
			||||||
	 * dispatching of the RTP data */
 | 
						 * dispatching of the RTP data */
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -46,8 +46,6 @@
 | 
				
			|||||||
#include <osmocom/mgcp/mgcp_sdp.h>
 | 
					#include <osmocom/mgcp/mgcp_sdp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_codec.h>
 | 
					#include <osmocom/mgcp/mgcp_codec.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_conn.h>
 | 
					#include <osmocom/mgcp/mgcp_conn.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_iuup.h>
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/debug.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Contains the last successfully resolved endpoint name. This variable is used
 | 
					/* Contains the last successfully resolved endpoint name. This variable is used
 | 
				
			||||||
 * for the unit-tests to verify that the endpoint was correctly resolved. */
 | 
					 * for the unit-tests to verify that the endpoint was correctly resolved. */
 | 
				
			||||||
@@ -99,6 +97,10 @@ struct mgcp_request {
 | 
				
			|||||||
	/* function pointer to the request handler */
 | 
						/* function pointer to the request handler */
 | 
				
			||||||
	struct msgb *(*handle_request)(struct mgcp_request_data *data);
 | 
						struct msgb *(*handle_request)(struct mgcp_request_data *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* true if the request requires an endpoint, false if only a trunk
 | 
				
			||||||
 | 
						 * is sufficient. (corner cases, e.g. wildcarded DLCX) */
 | 
				
			||||||
 | 
						bool require_endp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* a human readable name that describes the request */
 | 
						/* a human readable name that describes the request */
 | 
				
			||||||
	char *debug_name;
 | 
						char *debug_name;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -110,34 +112,32 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *data);
 | 
				
			|||||||
static struct msgb *handle_rsip(struct mgcp_request_data *data);
 | 
					static struct msgb *handle_rsip(struct mgcp_request_data *data);
 | 
				
			||||||
static struct msgb *handle_noti_req(struct mgcp_request_data *data);
 | 
					static struct msgb *handle_noti_req(struct mgcp_request_data *data);
 | 
				
			||||||
static const struct mgcp_request mgcp_requests[] = {
 | 
					static const struct mgcp_request mgcp_requests[] = {
 | 
				
			||||||
	{ .name = "AUEP", .handle_request = handle_audit_endpoint, .debug_name = "AuditEndpoint" },
 | 
						{ .name = "AUEP",
 | 
				
			||||||
	{
 | 
						  .handle_request = handle_audit_endpoint,
 | 
				
			||||||
		.name = "CRCX",
 | 
						  .debug_name = "AuditEndpoint",
 | 
				
			||||||
 | 
						  .require_endp = true },
 | 
				
			||||||
 | 
						{ .name = "CRCX",
 | 
				
			||||||
	  .handle_request = handle_create_con,
 | 
						  .handle_request = handle_create_con,
 | 
				
			||||||
	  .debug_name = "CreateConnection",
 | 
						  .debug_name = "CreateConnection",
 | 
				
			||||||
	},
 | 
						  .require_endp = true },
 | 
				
			||||||
	{
 | 
						{ .name = "DLCX",
 | 
				
			||||||
		.name = "DLCX",
 | 
					 | 
				
			||||||
	  .handle_request = handle_delete_con,
 | 
						  .handle_request = handle_delete_con,
 | 
				
			||||||
	  .debug_name = "DeleteConnection",
 | 
						  .debug_name = "DeleteConnection",
 | 
				
			||||||
	},
 | 
						  .require_endp = false },
 | 
				
			||||||
	{
 | 
						{ .name = "MDCX",
 | 
				
			||||||
		.name = "MDCX",
 | 
					 | 
				
			||||||
	  .handle_request = handle_modify_con,
 | 
						  .handle_request = handle_modify_con,
 | 
				
			||||||
	  .debug_name = "ModifiyConnection",
 | 
						  .debug_name = "ModifiyConnection",
 | 
				
			||||||
	},
 | 
						  .require_endp = true },
 | 
				
			||||||
	{
 | 
						{ .name = "RQNT",
 | 
				
			||||||
		.name = "RQNT",
 | 
					 | 
				
			||||||
	  .handle_request = handle_noti_req,
 | 
						  .handle_request = handle_noti_req,
 | 
				
			||||||
	  .debug_name = "NotificationRequest",
 | 
						  .debug_name = "NotificationRequest",
 | 
				
			||||||
	},
 | 
						  .require_endp = true },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* SPEC extension */
 | 
						/* SPEC extension */
 | 
				
			||||||
	{
 | 
						{ .name = "RSIP",
 | 
				
			||||||
		.name = "RSIP",
 | 
					 | 
				
			||||||
	  .handle_request = handle_rsip,
 | 
						  .handle_request = handle_rsip,
 | 
				
			||||||
	  .debug_name = "ReSetInProgress",
 | 
						  .debug_name = "ReSetInProgress",
 | 
				
			||||||
	},
 | 
						  .require_endp = true },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Initalize transcoder */
 | 
					/* Initalize transcoder */
 | 
				
			||||||
@@ -149,12 +149,7 @@ 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (conn->type) {
 | 
						if (conn->type != MGCP_RTP_DEFAULT && !mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
	case MGCP_RTP_DEFAULT:
 | 
					 | 
				
			||||||
	case MGCP_RTP_OSMUX:
 | 
					 | 
				
			||||||
	case MGCP_RTP_IUUP:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			 "RTP-setup: Endpoint is not configured as RTP default, stopping here!\n");
 | 
								 "RTP-setup: Endpoint is not configured as RTP default, stopping here!\n");
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -178,15 +173,12 @@ static int setup_rtp_processing(struct mgcp_endpoint *endp,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Helper function to allocate some memory for responses and retransmissions */
 | 
					/* Helper function to allocate some memory for responses and retransmissions */
 | 
				
			||||||
static struct msgb *mgcp_msgb_alloc(void *ctx)
 | 
					static struct msgb *mgcp_msgb_alloc(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
	msg = msgb_alloc_headroom_c(ctx, 4096, 128, "MGCP msg");
 | 
						msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
	if (!msg) {
 | 
					 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
 | 
							LOGP(DLMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -194,7 +186,7 @@ static struct msgb *mgcp_msgb_alloc(void *ctx)
 | 
				
			|||||||
/* Helper function for do_retransmission() and create_resp() */
 | 
					/* Helper function for do_retransmission() and create_resp() */
 | 
				
			||||||
static struct msgb *create_retransmission_response(const struct mgcp_endpoint *endp)
 | 
					static struct msgb *create_retransmission_response(const struct mgcp_endpoint *endp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = mgcp_msgb_alloc(endp->trunk);
 | 
						struct msgb *msg = mgcp_msgb_alloc();
 | 
				
			||||||
	if (!msg)
 | 
						if (!msg)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,14 +196,15 @@ static struct msgb *create_retransmission_response(const struct mgcp_endpoint *e
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *create_resp(void *msgctx, struct mgcp_endpoint *endp, int code, const char *txt, const char *msg,
 | 
					static struct msgb *create_resp(struct mgcp_endpoint *endp, int code,
 | 
				
			||||||
				const char *trans, const char *param, const char *sdp)
 | 
									const char *txt, const char *msg,
 | 
				
			||||||
 | 
									const char *trans, const char *param,
 | 
				
			||||||
 | 
									const char *sdp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int len;
 | 
						int len;
 | 
				
			||||||
	struct msgb *res;
 | 
						struct msgb *res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(msgctx != 0);
 | 
						res = mgcp_msgb_alloc();
 | 
				
			||||||
	res = mgcp_msgb_alloc(msgctx);
 | 
					 | 
				
			||||||
	if (!res)
 | 
						if (!res)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -243,22 +236,26 @@ static struct msgb *create_resp(void *msgctx, struct mgcp_endpoint *endp, int co
 | 
				
			|||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *create_ok_resp_with_param(void *msgctx, struct mgcp_endpoint *endp, int code, const char *msg,
 | 
					static struct msgb *create_ok_resp_with_param(struct mgcp_endpoint *endp,
 | 
				
			||||||
					      const char *trans, const char *param)
 | 
										      int code, const char *msg,
 | 
				
			||||||
 | 
										      const char *trans,
 | 
				
			||||||
 | 
										      const char *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return create_resp(msgctx, endp, code, " OK", msg, trans, param, NULL);
 | 
						return create_resp(endp, code, " OK", msg, trans, param, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *create_ok_response(void *msgctx, struct mgcp_endpoint *endp, int code, const char *msg,
 | 
					static struct msgb *create_ok_response(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
									       int code, const char *msg,
 | 
				
			||||||
				       const char *trans)
 | 
									       const char *trans)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return create_ok_resp_with_param(msgctx, endp, code, msg, trans, NULL);
 | 
						return create_ok_resp_with_param(endp, code, msg, trans, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct msgb *create_err_response(void *msgctx, struct mgcp_endpoint *endp, int code, const char *msg,
 | 
					static struct msgb *create_err_response(struct mgcp_endpoint *endp,
 | 
				
			||||||
 | 
										int code, const char *msg,
 | 
				
			||||||
					const char *trans)
 | 
										const char *trans)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return create_resp(msgctx, endp, code, " FAIL", msg, trans, NULL, NULL);
 | 
						return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Format MGCP response string (with SDP attached) */
 | 
					/* Format MGCP response string (with SDP attached) */
 | 
				
			||||||
@@ -281,7 +278,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct msgb *result;
 | 
						struct msgb *result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdp = msgb_alloc_headroom_c(endp->trunk, 4096, 128, "sdp record");
 | 
						sdp = msgb_alloc_headroom(4096, 128, "sdp record");
 | 
				
			||||||
	if (!sdp)
 | 
						if (!sdp)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,7 +298,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Attach optional OSMUX parameters */
 | 
						/* Attach optional OSMUX parameters */
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		rc = msgb_printf(sdp, MGCP_X_OSMO_OSMUX_HEADER " %u\r\n", conn->osmux.local_cid);
 | 
							rc = msgb_printf(sdp, "X-Osmux: %u\r\n", conn->osmux.cid);
 | 
				
			||||||
		if (rc < 0)
 | 
							if (rc < 0)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -312,7 +309,7 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
 | 
				
			|||||||
	rc = mgcp_write_response_sdp(endp, conn, sdp, addr);
 | 
						rc = mgcp_write_response_sdp(endp, conn, sdp, addr);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	result = create_resp(endp->trunk, endp, 200, " OK", msg, trans_id, NULL, (char *)sdp->data);
 | 
						result = create_resp(endp, 200, " OK", msg, trans_id, NULL, (char*) sdp->data);
 | 
				
			||||||
	msgb_free(sdp);
 | 
						msgb_free(sdp);
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
@@ -324,13 +321,8 @@ error:
 | 
				
			|||||||
 * osmux connection, send the dummy packet via OSMUX */
 | 
					 * osmux connection, send the dummy packet via OSMUX */
 | 
				
			||||||
static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
					static void send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Avoid sending dummy packet if the remote address was not yet
 | 
						if (conn->osmux.state != OSMUX_STATE_DISABLED)
 | 
				
			||||||
	 * configured through CRCX/MDCX: */
 | 
							osmux_send_dummy(endp, conn);
 | 
				
			||||||
	if (!mgcp_rtp_end_remote_addr_available(&conn->end))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn))
 | 
					 | 
				
			||||||
		osmux_send_dummy(conn);
 | 
					 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		mgcp_send_dummy(endp, conn);
 | 
							mgcp_send_dummy(endp, conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -384,7 +376,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGP(DLMGCP, LOGL_ERROR, "%s: failed to parse MCGP message\n", rq.name);
 | 
							LOGP(DLMGCP, LOGL_ERROR, "%s: failed to parse MCGP message\n", rq.name);
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_MSG_PARSE));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_MSG_PARSE));
 | 
				
			||||||
		return create_err_response(cfg, NULL, -rc, rq.name, "000000");
 | 
							return create_err_response(NULL, -rc, rq.name, "000000");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
 | 
						/* Locate endpoint and trunk, if no endpoint can be located try at least to identify the trunk. */
 | 
				
			||||||
@@ -405,7 +397,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
			if (!rq.trunk) {
 | 
								if (!rq.trunk) {
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_ERROR, "%s: failed to identify trunk for endpoint \"%s\" -- abort\n",
 | 
									LOGP(DLMGCP, LOGL_ERROR, "%s: failed to identify trunk for endpoint \"%s\" -- abort\n",
 | 
				
			||||||
				     rq.name, pdata.epname);
 | 
									     rq.name, pdata.epname);
 | 
				
			||||||
				return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
									return create_err_response(NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			/* If the endpoint name suggests that the request refers to a specific endpoint, then the
 | 
								/* If the endpoint name suggests that the request refers to a specific endpoint, then the
 | 
				
			||||||
@@ -413,7 +405,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
			LOGP(DLMGCP, LOGL_NOTICE,
 | 
								LOGP(DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
			     "%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
 | 
								     "%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq.name,
 | 
				
			||||||
			     pdata.epname, -rq.mgcp_cause);
 | 
								     pdata.epname, -rq.mgcp_cause);
 | 
				
			||||||
			return create_err_response(cfg, NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
								return create_err_response(NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
 | 
							osmo_strlcpy(debug_last_endpoint_name, rq.endp->name, sizeof(debug_last_endpoint_name));
 | 
				
			||||||
@@ -430,6 +422,15 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
	/* Find an appropriate handler for the current request and execute it */
 | 
						/* Find an appropriate handler for the current request and execute it */
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(mgcp_requests); i++) {
 | 
						for (i = 0; i < ARRAY_SIZE(mgcp_requests); i++) {
 | 
				
			||||||
		if (strcmp(mgcp_requests[i].name, rq.name) == 0) {
 | 
							if (strcmp(mgcp_requests[i].name, rq.name) == 0) {
 | 
				
			||||||
 | 
								/* Check if the request requires and endpoint, if yes, check if we have it, otherwise don't
 | 
				
			||||||
 | 
								 * execute the request handler. */
 | 
				
			||||||
 | 
								if (mgcp_requests[i].require_endp && !rq.endp) {
 | 
				
			||||||
 | 
									LOGP(DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
									     "%s: the request handler \"%s\" requires an endpoint resource for \"%s\", which is not available -- abort\n",
 | 
				
			||||||
 | 
									     rq.name, mgcp_requests[i].debug_name, pdata.epname);
 | 
				
			||||||
 | 
									return create_err_response(NULL, -rq.mgcp_cause, rq.name, pdata.trans);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* Execute request handler */
 | 
								/* Execute request handler */
 | 
				
			||||||
			if (rq.endp)
 | 
								if (rq.endp)
 | 
				
			||||||
				LOGP(DLMGCP, LOGL_INFO,
 | 
									LOGP(DLMGCP, LOGL_INFO,
 | 
				
			||||||
@@ -460,12 +461,7 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
 | 
				
			|||||||
static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
 | 
					static struct msgb *handle_audit_endpoint(struct mgcp_request_data *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
						LOGPENDP(rq->endp, DLMGCP, LOGL_NOTICE, "AUEP: auditing endpoint ...\n");
 | 
				
			||||||
	if (!rq->endp || !mgcp_endp_avail(rq->endp)) {
 | 
						return create_ok_response(rq->endp, 200, "AUEP", rq->pdata->trans);
 | 
				
			||||||
		LOGPENDP(rq->endp, DLMGCP, LOGL_ERROR, "AUEP: selected endpoint not available!\n");
 | 
					 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 501, "AUEP", rq->pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return create_ok_response(rq->trunk, rq->endp, 200, "AUEP", rq->pdata->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
 | 
				
			||||||
@@ -714,7 +710,7 @@ void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "Configuring RTP endpoint: local port %d%s%s\n",
 | 
							 "Configuring RTP endpoint: local port %d%s%s\n",
 | 
				
			||||||
		 osmo_sockaddr_port(&rtp->addr.u.sa),
 | 
							 ntohs(rtp->rtp_port),
 | 
				
			||||||
		 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
							 rtp->force_aligned_timing ? ", force constant timing" : "",
 | 
				
			||||||
		 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
 | 
							 rtp->force_constant_ssrc ? ", force constant ssrc" : "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -745,12 +741,12 @@ uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
 | 
					static int mgcp_osmux_setup(struct mgcp_endpoint *endp, const char *line)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!endp->trunk->cfg->osmux.initialized) {
 | 
						if (!endp->trunk->cfg->osmux_init) {
 | 
				
			||||||
		if (osmux_init(endp->trunk) < 0) {
 | 
							if (osmux_init(OSMUX_ROLE_BSC, endp->trunk->cfg) < 0) {
 | 
				
			||||||
			LOGPENDP(endp, DOSMUX, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
								LOGPENDP(endp, DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
 | 
				
			||||||
			return -3;
 | 
								return -3;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		LOGPENDP(endp, DOSMUX, 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);
 | 
				
			||||||
@@ -851,7 +847,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	const char *callid = NULL;
 | 
						const char *callid = NULL;
 | 
				
			||||||
	const char *mode = NULL;
 | 
						const char *mode = NULL;
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	int have_sdp = 0, remote_osmux_cid = -2;
 | 
						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];
 | 
				
			||||||
@@ -859,18 +855,11 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "CRCX: creating new connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we must have a free ep */
 | 
					 | 
				
			||||||
	if (!endp) {
 | 
					 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "CRCX: no free endpoints available!\n");
 | 
					 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 403, "CRCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!mgcp_endp_avail(endp)) {
 | 
						if (!mgcp_endp_avail(endp)) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: selected endpoint not available!\n");
 | 
								 "CRCX: selected endpoint not available!\n");
 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 501, "CRCX", pdata->trans);
 | 
							return create_err_response(NULL, 501, "CRCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse CallID C: and LocalParameters L: */
 | 
						/* parse CallID C: and LocalParameters L: */
 | 
				
			||||||
@@ -890,7 +879,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
			 * together with a CRCX, the MGW will assign the
 | 
								 * together with a CRCX, the MGW will assign the
 | 
				
			||||||
			 * connection identifier by itself on CRCX */
 | 
								 * connection identifier by itself on CRCX */
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BAD_ACTION));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BAD_ACTION));
 | 
				
			||||||
			return create_err_response(rq->trunk, NULL, 523, "CRCX", pdata->trans);
 | 
								return create_err_response(NULL, 523, "CRCX", pdata->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case 'M':
 | 
							case 'M':
 | 
				
			||||||
			mode = (const char *)line + 3;
 | 
								mode = (const char *)line + 3;
 | 
				
			||||||
@@ -898,9 +887,9 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		case 'X':
 | 
							case 'X':
 | 
				
			||||||
			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
				/* If osmux is disabled, just skip setting it up */
 | 
									/* If osmux is disabled, just skip setting it up */
 | 
				
			||||||
				if (rq->endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
 | 
									if (!rq->endp->trunk->cfg->osmux)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				remote_osmux_cid = mgcp_osmux_setup(endp, line);
 | 
									osmux_cid = mgcp_osmux_setup(endp, line);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -916,7 +905,7 @@ static struct msgb *handle_create_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
			LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
								LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
				 "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
									 "CRCX: unhandled option: '%c'/%d\n", *line, *line);
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNHANDLED_PARAM));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNHANDLED_PARAM));
 | 
				
			||||||
			return create_err_response(rq->trunk, NULL, 539, "CRCX", pdata->trans);
 | 
								return create_err_response(NULL, 539, "CRCX", pdata->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -927,14 +916,14 @@ mgcp_header_done:
 | 
				
			|||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: insufficient parameters, missing callid\n");
 | 
								 "CRCX: insufficient parameters, missing callid\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_MISSING_CALLID));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_MISSING_CALLID));
 | 
				
			||||||
		return create_err_response(endp, endp, 516, "CRCX", pdata->trans);
 | 
							return create_err_response(endp, 516, "CRCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!mode) {
 | 
						if (!mode) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: insufficient parameters, missing mode\n");
 | 
								 "CRCX: insufficient parameters, missing mode\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
 | 
				
			||||||
		return create_err_response(endp, endp, 517, "CRCX", pdata->trans);
 | 
							return create_err_response(endp, 517, "CRCX", pdata->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 */
 | 
				
			||||||
@@ -951,7 +940,7 @@ mgcp_header_done:
 | 
				
			|||||||
			/* There is no more room for a connection, leave
 | 
								/* There is no more room for a connection, leave
 | 
				
			||||||
			 * everything as it is and return with an error */
 | 
								 * everything as it is and return with an error */
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_LIMIT_EXCEEDED));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_LIMIT_EXCEEDED));
 | 
				
			||||||
			return create_err_response(endp, endp, 540, "CRCX", pdata->trans);
 | 
								return create_err_response(endp, 540, "CRCX", pdata->trans);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -969,7 +958,7 @@ mgcp_header_done:
 | 
				
			|||||||
			/* This is not our call, leave everything as it is and
 | 
								/* This is not our call, leave everything as it is and
 | 
				
			||||||
			 * return with an error. */
 | 
								 * return with an error. */
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNKNOWN_CALLID));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNKNOWN_CALLID));
 | 
				
			||||||
			return create_err_response(endp, endp, 400, "CRCX", pdata->trans);
 | 
								return create_err_response(endp, 400, "CRCX", pdata->trans);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -980,7 +969,7 @@ mgcp_header_done:
 | 
				
			|||||||
		rc = mgcp_endp_claim(endp, callid);
 | 
							rc = mgcp_endp_claim(endp, callid);
 | 
				
			||||||
		if (rc != 0) {
 | 
							if (rc != 0) {
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CLAIM));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CLAIM));
 | 
				
			||||||
			return create_err_response(endp, endp, 502, "CRCX", pdata->trans);
 | 
								return create_err_response(endp, 502, "CRCX", pdata->trans);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1003,17 +992,16 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If X-Osmux (remote CID) was received (-1 is wilcard), alloc next avail CID as local CID */
 | 
						/* Annotate Osmux circuit ID and set it to negotiating state until this
 | 
				
			||||||
	if (remote_osmux_cid >= -1) {
 | 
						 * is fully set up from the dummy load. */
 | 
				
			||||||
		if (osmux_init_conn(conn) < 0) {
 | 
						conn->osmux.state = OSMUX_STATE_DISABLED;
 | 
				
			||||||
 | 
						if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
 | 
				
			||||||
 | 
							conn->osmux.state = OSMUX_STATE_ACTIVATING;
 | 
				
			||||||
 | 
							if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
				
			||||||
			goto error2;
 | 
								goto error2;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (remote_osmux_cid >= 0) {
 | 
						} else if (endp->trunk->cfg->osmux == OSMUX_USAGE_ONLY) {
 | 
				
			||||||
			conn->osmux.remote_cid_present = true;
 | 
					 | 
				
			||||||
			conn->osmux.remote_cid = remote_osmux_cid;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_ONLY) {
 | 
					 | 
				
			||||||
		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: osmux only and no osmux offered\n");
 | 
								 "CRCX: osmux only and no osmux offered\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
 | 
				
			||||||
@@ -1041,11 +1029,6 @@ mgcp_header_done:
 | 
				
			|||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Upgrade the conn type RTP_DEFAULT->RTP_IUUP if needed based on requested codec: */
 | 
					 | 
				
			||||||
	/* TODO: "codec" probably needs to be moved from endp to conn */
 | 
					 | 
				
			||||||
	if (conn->type == MGCP_RTP_DEFAULT && strcmp(conn->end.codec->subtype_name, "VND.3GPP.IUFP") == 0) {
 | 
					 | 
				
			||||||
		rc = mgcp_conn_iuup_init(conn);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
 | 
						conn->end.fmtp_extra = talloc_strdup(trunk->endpoints,
 | 
				
			||||||
					     trunk->audio_fmtp_extra);
 | 
										     trunk->audio_fmtp_extra);
 | 
				
			||||||
@@ -1060,7 +1043,7 @@ mgcp_header_done:
 | 
				
			|||||||
	/* check connection mode setting */
 | 
						/* check connection mode setting */
 | 
				
			||||||
	if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
						if (conn->conn->mode != MGCP_CONN_LOOPBACK
 | 
				
			||||||
	    && conn->conn->mode != MGCP_CONN_RECV_ONLY
 | 
						    && conn->conn->mode != MGCP_CONN_RECV_ONLY
 | 
				
			||||||
	    && osmo_sockaddr_port(&conn->end.addr.u.sa) == 0) {
 | 
						    && conn->end.rtp_port == 0) {
 | 
				
			||||||
		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
							LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "CRCX: selected connection mode type requires an opposite end!\n");
 | 
								 "CRCX: selected connection mode type requires an opposite end!\n");
 | 
				
			||||||
		error_code = 527;
 | 
							error_code = 527;
 | 
				
			||||||
@@ -1070,10 +1053,7 @@ mgcp_header_done:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* Find a local address for conn based on policy and initial SDP remote
 | 
						/* Find a local address for conn based on policy and initial SDP remote
 | 
				
			||||||
	   information, then find a free port for it */
 | 
						   information, then find a free port for it */
 | 
				
			||||||
	if (mgcp_get_local_addr(conn->end.local_addr, conn) < 0) {
 | 
						mgcp_get_local_addr(conn->end.local_addr, conn);
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
					 | 
				
			||||||
		goto error2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (allocate_port(endp, conn) != 0) {
 | 
						if (allocate_port(endp, conn) != 0) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
				
			||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
@@ -1086,20 +1066,13 @@ mgcp_header_done:
 | 
				
			|||||||
		goto error2;
 | 
							goto error2;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Notify Osmux conn that CRCX was received */
 | 
					 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
					 | 
				
			||||||
		if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
 | 
					 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "CRCX: Osmux handling failed!\n");
 | 
					 | 
				
			||||||
			goto error2;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
 | 
				
			||||||
		 "CRCX: Creating connection: port: %u\n", conn->end.local_port);
 | 
							 "CRCX: Creating connection: port: %u\n", conn->end.local_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
						OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
	if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
 | 
						if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
 | 
				
			||||||
 | 
						    mgcp_rtp_end_remote_addr_available(&conn->end) &&
 | 
				
			||||||
	    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1115,7 +1088,7 @@ error2:
 | 
				
			|||||||
	mgcp_endp_release(endp);
 | 
						mgcp_endp_release(endp);
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
		 "CRCX: unable to create connection\n");
 | 
							 "CRCX: unable to create connection\n");
 | 
				
			||||||
	return create_err_response(endp, endp, error_code, "CRCX", pdata->trans);
 | 
						return create_err_response(endp, error_code, "CRCX", pdata->trans);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* MDCX command handler, processes the received command */
 | 
					/* MDCX command handler, processes the received command */
 | 
				
			||||||
@@ -1134,29 +1107,31 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	const char *mode = NULL;
 | 
						const char *mode = NULL;
 | 
				
			||||||
	struct mgcp_conn_rtp *conn = NULL;
 | 
						struct mgcp_conn_rtp *conn = NULL;
 | 
				
			||||||
        const char *conn_id = NULL;
 | 
					        const char *conn_id = NULL;
 | 
				
			||||||
	int remote_osmux_cid = -2;
 | 
						int osmux_cid = -2;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "MDCX: modifying existing connection ...\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mgcp_endp_avail(endp)) {
 | 
				
			||||||
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_AVAIL));
 | 
				
			||||||
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
 | 
								 "MDCX: selected endpoint not available!\n");
 | 
				
			||||||
 | 
							return create_err_response(NULL, 501, "MDCX", pdata->trans);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Prohibit wildcarded requests */
 | 
						/* Prohibit wildcarded requests */
 | 
				
			||||||
	if (rq->wildcarded) {
 | 
						if (rq->wildcarded) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "MDCX: wildcarded endpoint names not supported.\n");
 | 
								 "MDCX: wildcarded endpoint names not supported.\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_WILDCARD));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_WILDCARD));
 | 
				
			||||||
		return create_err_response(rq->trunk, endp, 507, "MDCX", pdata->trans);
 | 
							return create_err_response(endp, 507, "MDCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!endp || !mgcp_endp_avail(endp)) {
 | 
					 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_AVAIL));
 | 
					 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "MDCX: selected endpoint not available!\n");
 | 
					 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 501, "MDCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (llist_count(&endp->conns) <= 0) {
 | 
						if (llist_count(&endp->conns) <= 0) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "MDCX: endpoint is not holding a connection.\n");
 | 
								 "MDCX: endpoint is not holding a connection.\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONN));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONN));
 | 
				
			||||||
		return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
 | 
							return create_err_response(endp, 400, "MDCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_line(line, pdata->save) {
 | 
						for_each_line(line, pdata->save) {
 | 
				
			||||||
@@ -1190,9 +1165,9 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		case 'X':
 | 
							case 'X':
 | 
				
			||||||
			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
								if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) {
 | 
				
			||||||
				/* If osmux is disabled, just skip setting it up */
 | 
									/* If osmux is disabled, just skip setting it up */
 | 
				
			||||||
				if (endp->trunk->cfg->osmux.usage == OSMUX_USAGE_OFF)
 | 
									if (!endp->trunk->cfg->osmux)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				remote_osmux_cid = mgcp_osmux_setup(endp, line);
 | 
									osmux_cid = mgcp_osmux_setup(endp, line);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/* Ignore unknown X-headers */
 | 
								/* Ignore unknown X-headers */
 | 
				
			||||||
@@ -1206,7 +1181,7 @@ static struct msgb *handle_modify_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
				 "MDCX: Unhandled MGCP option: '%c'/%d\n",
 | 
									 "MDCX: Unhandled MGCP option: '%c'/%d\n",
 | 
				
			||||||
				 line[0], line[0]);
 | 
									 line[0], line[0]);
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_UNHANDLED_PARAM));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_UNHANDLED_PARAM));
 | 
				
			||||||
			return create_err_response(rq->trunk, NULL, 539, "MDCX", pdata->trans);
 | 
								return create_err_response(NULL, 539, "MDCX", pdata->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1216,13 +1191,13 @@ mgcp_header_done:
 | 
				
			|||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "MDCX: insufficient parameters, missing ci (connectionIdentifier)\n");
 | 
								 "MDCX: insufficient parameters, missing ci (connectionIdentifier)\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONNID));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONNID));
 | 
				
			||||||
		return create_err_response(endp, endp, 515, "MDCX", pdata->trans);
 | 
							return create_err_response(endp, 515, "MDCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	if (!conn) {
 | 
						if (!conn) {
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_CONN_NOT_FOUND));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_CONN_NOT_FOUND));
 | 
				
			||||||
		return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
 | 
							return create_err_response(endp, 400, "MDCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgcp_conn_watchdog_kick(conn->conn);
 | 
						mgcp_conn_watchdog_kick(conn->conn);
 | 
				
			||||||
@@ -1269,39 +1244,30 @@ mgcp_header_done:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
						if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
				
			||||||
		OSMO_ASSERT(conn->osmux.local_cid_allocated);
 | 
							OSMO_ASSERT(conn->osmux.cid_allocated);
 | 
				
			||||||
		if (remote_osmux_cid < -1) {
 | 
							if (osmux_cid < -1) {
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "MDCX: Failed to parse Osmux CID!\n");
 | 
									 "MDCX: Failed to parse Osmux CID!\n");
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
		} else if (remote_osmux_cid == -1) {
 | 
							} else if (osmux_cid == -1) {
 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "MDCX: wilcard in MDCX is not supported!\n");
 | 
									 "MDCX: wilcard in MDCX is not supported!\n");
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
		} else if (conn->osmux.remote_cid_present &&
 | 
							} else if (osmux_cid != (int) conn->osmux.cid) {
 | 
				
			||||||
				remote_osmux_cid != conn->osmux.remote_cid) {
 | 
					 | 
				
			||||||
			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
								LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
				 "MDCX: changing already allocated CID is not supported!\n");
 | 
									 "MDCX: changing already allocated CID is not supported!\n");
 | 
				
			||||||
			goto error3;
 | 
								goto error3;
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			conn->osmux.remote_cid_present = true;
 | 
					 | 
				
			||||||
			conn->osmux.remote_cid = remote_osmux_cid;
 | 
					 | 
				
			||||||
			if (conn_osmux_event_rx_crcx_mdcx(conn) < 0) {
 | 
					 | 
				
			||||||
				LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 | 
					 | 
				
			||||||
					"MDCX: Osmux handling failed!\n");
 | 
					 | 
				
			||||||
				goto error3;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							/* TODO: In the future (when we have recvCID!=sendCID), we need to
 | 
				
			||||||
 | 
							   tell Osmux code that osmux_cid is to be used as sendCID for
 | 
				
			||||||
 | 
							   that conn. */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* MDCX may have provided a new remote address, which means we may need
 | 
						/* MDCX may have provided a new remote address, which means we may need
 | 
				
			||||||
	   to update our announced IP addr and re-bind our local end. This can
 | 
						   to update our announced IP addr and re-bind our local end. This can
 | 
				
			||||||
	   happen for instance if MGW initially provided an IPv4 during CRCX
 | 
						   happen for instance if MGW initially provided an IPv4 during CRCX
 | 
				
			||||||
	   ACK, and now MDCX tells us the remote has an IPv6 address. */
 | 
						   ACK, and now MDCX tells us the remote has an IPv6 address. */
 | 
				
			||||||
	if (mgcp_get_local_addr(new_local_addr, conn) < 0) {
 | 
						mgcp_get_local_addr(new_local_addr, conn);
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
 | 
					 | 
				
			||||||
		goto error3;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (strcmp(new_local_addr, conn->end.local_addr)) {
 | 
						if (strcmp(new_local_addr, conn->end.local_addr)) {
 | 
				
			||||||
		osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 | 
							osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 | 
				
			||||||
		mgcp_free_rtp_port(&conn->end);
 | 
							mgcp_free_rtp_port(&conn->end);
 | 
				
			||||||
@@ -1325,6 +1291,7 @@ mgcp_header_done:
 | 
				
			|||||||
	/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
						/* Send dummy packet, see also comments in mgcp_keepalive_timer_cb() */
 | 
				
			||||||
	OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
						OSMO_ASSERT(trunk->keepalive_interval >= MGCP_KEEPALIVE_ONCE);
 | 
				
			||||||
	if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
 | 
						if (conn->conn->mode & MGCP_CONN_RECV_ONLY &&
 | 
				
			||||||
 | 
						    mgcp_rtp_end_remote_addr_available(&conn->end) &&
 | 
				
			||||||
	    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
						    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 | 
				
			||||||
		send_dummy(endp, conn);
 | 
							send_dummy(endp, conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1337,7 +1304,7 @@ mgcp_header_done:
 | 
				
			|||||||
	mgcp_endp_update(endp);
 | 
						mgcp_endp_update(endp);
 | 
				
			||||||
	return create_response_with_sdp(endp, conn, "MDCX", pdata->trans, false, false);
 | 
						return create_response_with_sdp(endp, conn, "MDCX", pdata->trans, false, false);
 | 
				
			||||||
error3:
 | 
					error3:
 | 
				
			||||||
	return create_err_response(endp, endp, error_code, "MDCX", pdata->trans);
 | 
						return create_err_response(endp, error_code, "MDCX", pdata->trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_silent:
 | 
					out_silent:
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "MDCX: silent exit\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "MDCX: silent exit\n");
 | 
				
			||||||
@@ -1368,27 +1335,14 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "DLCX: selected endpoint not available!\n");
 | 
								 "DLCX: selected endpoint not available!\n");
 | 
				
			||||||
		return create_err_response(rq->trunk, NULL, 501, "DLCX", pdata->trans);
 | 
							return create_err_response(NULL, 501, "DLCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (endp && !rq->wildcarded && llist_empty(&endp->conns)) {
 | 
						if (endp && !rq->wildcarded && llist_empty(&endp->conns)) {
 | 
				
			||||||
		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
							LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 | 
				
			||||||
			 "DLCX: endpoint is not holding a connection.\n");
 | 
								 "DLCX: endpoint is not holding a connection.\n");
 | 
				
			||||||
		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_NO_CONN));
 | 
							rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_NO_CONN));
 | 
				
			||||||
		return create_err_response(endp, endp, 515, "DLCX", pdata->trans);
 | 
							return create_err_response(endp, 515, "DLCX", pdata->trans);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Handle wildcarded DLCX that refers to the whole trunk. This means
 | 
					 | 
				
			||||||
	 * that we walk over all endpoints on the trunk in order to drop all
 | 
					 | 
				
			||||||
	 * connections on the trunk. (see also RFC3435 Annex F.7) */
 | 
					 | 
				
			||||||
	if (rq->wildcarded) {
 | 
					 | 
				
			||||||
		int num_conns = 0;
 | 
					 | 
				
			||||||
		for (i = 0; i < trunk->number_endpoints; i++) {
 | 
					 | 
				
			||||||
			num_conns += llist_count(&trunk->endpoints[i]->conns);
 | 
					 | 
				
			||||||
			mgcp_endp_release(trunk->endpoints[i]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rate_ctr_add(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS), num_conns);
 | 
					 | 
				
			||||||
		return create_ok_response(trunk, NULL, 200, "DLCX", pdata->trans);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_line(line, pdata->save) {
 | 
						for_each_line(line, pdata->save) {
 | 
				
			||||||
@@ -1403,7 +1357,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
				LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 | 
									LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
					  "cannot handle requests with call-id (C) without endpoint -- abort!");
 | 
										  "cannot handle requests with call-id (C) without endpoint -- abort!");
 | 
				
			||||||
				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
									rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
				
			||||||
				return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 | 
									return create_err_response(NULL, 539, "DLCX", pdata->trans);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
								if (mgcp_verify_call_id(endp, line + 3) != 0) {
 | 
				
			||||||
@@ -1419,7 +1373,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
				LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 | 
									LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
					  "cannot handle requests with conn-id (I) without endpoint -- abort!");
 | 
										  "cannot handle requests with conn-id (I) without endpoint -- abort!");
 | 
				
			||||||
				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
									rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
				
			||||||
				return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 | 
									return create_err_response(NULL, 539, "DLCX", pdata->trans);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			conn_id = (const char *)line + 3;
 | 
								conn_id = (const char *)line + 3;
 | 
				
			||||||
@@ -1435,11 +1389,24 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
			LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: Unhandled MGCP option: '%c'/%d\n",
 | 
								LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: Unhandled MGCP option: '%c'/%d\n",
 | 
				
			||||||
				 line[0], line[0]);
 | 
									 line[0], line[0]);
 | 
				
			||||||
			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
								rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
 | 
				
			||||||
			return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 | 
								return create_err_response(NULL, 539, "DLCX", pdata->trans);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle wildcarded DLCX that refers to the whole trunk. This means
 | 
				
			||||||
 | 
						 * that we walk over all endpoints on the trunk in order to drop all
 | 
				
			||||||
 | 
						 * connections on the trunk. (see also RFC3435 Annex F.7) */
 | 
				
			||||||
 | 
						if (rq->wildcarded) {
 | 
				
			||||||
 | 
							int num_conns = 0;
 | 
				
			||||||
 | 
							for (i = 0; i < trunk->number_endpoints; i++) {
 | 
				
			||||||
 | 
								num_conns += llist_count(&trunk->endpoints[i]->conns);
 | 
				
			||||||
 | 
								mgcp_endp_release(trunk->endpoints[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rate_ctr_add(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS), num_conns);
 | 
				
			||||||
 | 
							return create_ok_response(NULL, 200, "DLCX", pdata->trans);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The logic does not permit to go past this point without having the
 | 
						/* The logic does not permit to go past this point without having the
 | 
				
			||||||
	 * the endp pointer populated. */
 | 
						 * the endp pointer populated. */
 | 
				
			||||||
	OSMO_ASSERT(endp);
 | 
						OSMO_ASSERT(endp);
 | 
				
			||||||
@@ -1462,7 +1429,7 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
		/* Note: In this case we do not return any statistics,
 | 
							/* Note: In this case we do not return any statistics,
 | 
				
			||||||
		 * as we assume that the client is not interested in
 | 
							 * as we assume that the client is not interested in
 | 
				
			||||||
		 * this case. */
 | 
							 * this case. */
 | 
				
			||||||
		return create_ok_response(endp, endp, 200, "DLCX", pdata->trans);
 | 
							return create_ok_response(endp, 200, "DLCX", pdata->trans);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Find the connection */
 | 
						/* Find the connection */
 | 
				
			||||||
@@ -1491,10 +1458,10 @@ static struct msgb *handle_delete_con(struct mgcp_request_data *rq)
 | 
				
			|||||||
	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS));
 | 
						rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS));
 | 
				
			||||||
	if (silent)
 | 
						if (silent)
 | 
				
			||||||
		goto out_silent;
 | 
							goto out_silent;
 | 
				
			||||||
	return create_ok_resp_with_param(endp, endp, 250, "DLCX", pdata->trans, stats);
 | 
						return create_ok_resp_with_param(endp, 250, "DLCX", pdata->trans, stats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error3:
 | 
					error3:
 | 
				
			||||||
	return create_err_response(endp, endp, error_code, "DLCX", pdata->trans);
 | 
						return create_err_response(endp, error_code, "DLCX", pdata->trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_silent:
 | 
					out_silent:
 | 
				
			||||||
	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "DLCX: silent exit\n");
 | 
						LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "DLCX: silent exit\n");
 | 
				
			||||||
@@ -1549,13 +1516,14 @@ static struct msgb *handle_noti_req(struct mgcp_request_data *rq)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* we didn't see a signal request with a tone */
 | 
						/* we didn't see a signal request with a tone */
 | 
				
			||||||
	if (tone == CHAR_MAX)
 | 
						if (tone == CHAR_MAX)
 | 
				
			||||||
		return create_ok_response(rq->endp, rq->endp, 200, "RQNT", rq->pdata->trans);
 | 
							return create_ok_response(rq->endp, 200, "RQNT", rq->pdata->trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rq->pdata->cfg->rqnt_cb)
 | 
						if (rq->pdata->cfg->rqnt_cb)
 | 
				
			||||||
		res = rq->pdata->cfg->rqnt_cb(rq->endp, tone);
 | 
							res = rq->pdata->cfg->rqnt_cb(rq->endp, tone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return res == 0 ? create_ok_response(rq->endp, rq->endp, 200, "RQNT", rq->pdata->trans) :
 | 
						return res == 0 ?
 | 
				
			||||||
				create_err_response(rq->endp, rq->endp, res, "RQNT", rq->pdata->trans);
 | 
						    create_ok_response(rq->endp, 200, "RQNT", rq->pdata->trans) :
 | 
				
			||||||
 | 
						    create_err_response(rq->endp, res, "RQNT", rq->pdata->trans);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Connection keepalive timer, will take care that dummy packets are send
 | 
					/* Connection keepalive timer, will take care that dummy packets are send
 | 
				
			||||||
@@ -1593,7 +1561,8 @@ static void mgcp_keepalive_timer_cb(void *_trunk)
 | 
				
			|||||||
		struct mgcp_endpoint *endp = trunk->endpoints[i];
 | 
							struct mgcp_endpoint *endp = trunk->endpoints[i];
 | 
				
			||||||
		llist_for_each_entry(conn, &endp->conns, entry) {
 | 
							llist_for_each_entry(conn, &endp->conns, entry) {
 | 
				
			||||||
			if (conn->type == MGCP_CONN_TYPE_RTP &&
 | 
								if (conn->type == MGCP_CONN_TYPE_RTP &&
 | 
				
			||||||
			    conn->mode == MGCP_CONN_RECV_ONLY)
 | 
								    conn->mode == MGCP_CONN_RECV_ONLY &&
 | 
				
			||||||
 | 
								     mgcp_rtp_end_remote_addr_available(&conn->u.rtp.end))
 | 
				
			||||||
				send_dummy(endp, &conn->u.rtp);
 | 
									send_dummy(endp, &conn->u.rtp);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1647,6 +1616,7 @@ struct mgcp_config *mgcp_config_alloc(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cfg->source_port = 2427;
 | 
						cfg->source_port = 2427;
 | 
				
			||||||
	osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
 | 
						osmo_strlcpy(cfg->source_addr, "0.0.0.0", sizeof(cfg->source_addr));
 | 
				
			||||||
 | 
						osmo_strlcpy(cfg->osmux_addr, "0.0.0.0", sizeof(cfg->osmux_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
 | 
						cfg->rtp_processing_cb = &mgcp_rtp_processing_default;
 | 
				
			||||||
	cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
 | 
						cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
 | 
				
			|||||||
	    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
						    { "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mgcp",
 | 
						.group_name_prefix = "mgcp",
 | 
				
			||||||
	.group_description = "mgcp general statistics",
 | 
						.group_description = "mgcp general statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -71,7 +71,7 @@ static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
						[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "crcx",
 | 
						.group_name_prefix = "crcx",
 | 
				
			||||||
	.group_description = "crxc statistics",
 | 
						.group_description = "crxc statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -97,7 +97,7 @@ static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "mdcx",
 | 
						.group_name_prefix = "mdcx",
 | 
				
			||||||
	.group_description = "mdcx statistics",
 | 
						.group_description = "mdcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -116,7 +116,7 @@ static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
 | 
				
			|||||||
	[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
						[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "dlcx",
 | 
						.group_name_prefix = "dlcx",
 | 
				
			||||||
	.group_description = "dlcx statistics",
 | 
						.group_description = "dlcx statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -130,7 +130,7 @@ static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
 | 
				
			|||||||
	[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
 | 
						[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "e1",
 | 
						.group_name_prefix = "e1",
 | 
				
			||||||
	.group_description = "e1 statistics",
 | 
						.group_description = "e1 statistics",
 | 
				
			||||||
	.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
						.class_id = OSMO_STATS_CLASS_GLOBAL,
 | 
				
			||||||
@@ -138,7 +138,7 @@ static const struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = e1_rate_ctr_desc
 | 
						.ctr_desc = e1_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
					const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			||||||
	.group_name_prefix = "all_rtp_conn",
 | 
						.group_name_prefix = "all_rtp_conn",
 | 
				
			||||||
	.group_description = "aggregated statistics for all rtp connections",
 | 
						.group_description = "aggregated statistics for all rtp connections",
 | 
				
			||||||
	.class_id = 1,
 | 
						.class_id = 1,
 | 
				
			||||||
@@ -146,14 +146,6 @@ static const struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
 | 
				
			|||||||
	.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
						.ctr_desc = all_rtp_conn_rate_ctr_desc
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct rate_ctr_group_desc all_osmux_conn_rate_ctr_group_desc = {
 | 
					 | 
				
			||||||
	.group_name_prefix = "all_osmux_conn",
 | 
					 | 
				
			||||||
	.group_description = "aggregated statistics for all osmux connections",
 | 
					 | 
				
			||||||
	.class_id = 1,
 | 
					 | 
				
			||||||
	.num_ctr = ARRAY_SIZE(all_osmux_conn_rate_ctr_desc),
 | 
					 | 
				
			||||||
	.ctr_desc = all_osmux_conn_rate_ctr_desc
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! allocate global rate counters
 | 
					/*! allocate global rate counters
 | 
				
			||||||
 *  (called once at startup).
 | 
					 *  (called once at startup).
 | 
				
			||||||
 *  \param[in] cfg mgw configuration for which the rate counters are allocated.
 | 
					 *  \param[in] cfg mgw configuration for which the rate counters are allocated.
 | 
				
			||||||
@@ -199,7 +191,6 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			|||||||
	static atomic_uint mdcx_rate_ctr_index = 0;
 | 
						static atomic_uint mdcx_rate_ctr_index = 0;
 | 
				
			||||||
	static atomic_uint dlcx_rate_ctr_index = 0;
 | 
						static atomic_uint dlcx_rate_ctr_index = 0;
 | 
				
			||||||
	static atomic_uint all_rtp_conn_rate_ctr_index = 0;
 | 
						static atomic_uint all_rtp_conn_rate_ctr_index = 0;
 | 
				
			||||||
	static atomic_uint all_osmux_conn_rate_ctr_index = 0;
 | 
					 | 
				
			||||||
	char ctr_name[256];
 | 
						char ctr_name[256];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
						if (ratectr->mgcp_crcx_ctr_group == NULL) {
 | 
				
			||||||
@@ -238,15 +229,6 @@ int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
 | 
				
			|||||||
			 trunk->trunk_nr);
 | 
								 trunk->trunk_nr);
 | 
				
			||||||
		rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
 | 
							rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->all_osmux_conn_stats == NULL) {
 | 
					 | 
				
			||||||
		ratectr->all_osmux_conn_stats = rate_ctr_group_alloc(trunk, &all_osmux_conn_rate_ctr_group_desc,
 | 
					 | 
				
			||||||
								   all_osmux_conn_rate_ctr_index++);
 | 
					 | 
				
			||||||
		if (!ratectr->all_osmux_conn_stats)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		snprintf(ctr_name, sizeof(ctr_name), "%s-%u:osmux_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
 | 
					 | 
				
			||||||
			 trunk->trunk_nr);
 | 
					 | 
				
			||||||
		rate_ctr_group_set_name(ratectr->all_osmux_conn_stats, ctr_name);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* E1 specific */
 | 
						/* E1 specific */
 | 
				
			||||||
	if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
 | 
						if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
 | 
				
			||||||
@@ -283,10 +265,6 @@ void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
 | 
				
			|||||||
		rate_ctr_group_free(ratectr->all_rtp_conn_stats);
 | 
							rate_ctr_group_free(ratectr->all_rtp_conn_stats);
 | 
				
			||||||
		ratectr->all_rtp_conn_stats = NULL;
 | 
							ratectr->all_rtp_conn_stats = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->all_osmux_conn_stats) {
 | 
					 | 
				
			||||||
		rate_ctr_group_free(ratectr->all_osmux_conn_stats);
 | 
					 | 
				
			||||||
		ratectr->all_osmux_conn_stats = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* E1 specific */
 | 
						/* E1 specific */
 | 
				
			||||||
	if (ratectr->e1_stats) {
 | 
						if (ratectr->e1_stats) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,7 +98,7 @@ static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
 | 
				
			|||||||
/* Helper function to update codec map information with additional data from
 | 
					/* Helper function to update codec map information with additional data from
 | 
				
			||||||
 * SDP, called from: mgcp_parse_sdp_data() */
 | 
					 * SDP, called from: mgcp_parse_sdp_data() */
 | 
				
			||||||
static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
					static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			||||||
			  int payload_type, const char *audio_name)
 | 
								  int payload, const char *audio_name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,7 +110,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			|||||||
		/* Note: We can only update payload codecs that already exist
 | 
							/* Note: We can only update payload codecs that already exist
 | 
				
			||||||
		 * in our codec list. If we get an unexpected payload type,
 | 
							 * in our codec list. If we get an unexpected payload type,
 | 
				
			||||||
		 * we just drop it */
 | 
							 * we just drop it */
 | 
				
			||||||
		if (codecs[i].payload_type != payload_type)
 | 
							if (codecs[i].payload_type != payload)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
							if (sscanf(audio_name, "%63[^/]/%d/%d",
 | 
				
			||||||
@@ -127,7 +127,7 @@ static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload_type,
 | 
						LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
 | 
				
			||||||
	     audio_name);
 | 
						     audio_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -334,7 +334,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
	void *tmp_ctx = talloc_new(NULL);
 | 
						void *tmp_ctx = talloc_new(NULL);
 | 
				
			||||||
	struct mgcp_rtp_end *rtp;
 | 
						struct mgcp_rtp_end *rtp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int payload_type;
 | 
						int payload;
 | 
				
			||||||
	int ptime, ptime2 = 0;
 | 
						int ptime, ptime2 = 0;
 | 
				
			||||||
	char audio_name[64];
 | 
						char audio_name[64];
 | 
				
			||||||
	int port, rc;
 | 
						int port, rc;
 | 
				
			||||||
@@ -355,8 +355,8 @@ 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", &payload_type, audio_name) == 2) {
 | 
								if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
 | 
				
			||||||
				codecs_update(tmp_ctx, codecs, codecs_used, payload_type, audio_name);
 | 
									codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -384,7 +384,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
		case 'm':
 | 
							case 'm':
 | 
				
			||||||
			rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
								rc = sscanf(line, "m=audio %d RTP/AVP", &port);
 | 
				
			||||||
			if (rc == 1) {
 | 
								if (rc == 1) {
 | 
				
			||||||
				osmo_sockaddr_set_port(&rtp->addr.u.sa, port);
 | 
									rtp->rtp_port = htons(port);
 | 
				
			||||||
				rtp->rtcp_port = htons(port + 1);
 | 
									rtp->rtcp_port = htons(port + 1);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -432,7 +432,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
						LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
 | 
				
			||||||
	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
						     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
 | 
				
			||||||
	     osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
						     ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
 | 
				
			||||||
	     rtp->packet_duration_ms);
 | 
						     rtp->packet_duration_ms);
 | 
				
			||||||
	if (codecs_used == 0)
 | 
						if (codecs_used == 0)
 | 
				
			||||||
		LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
							LOGPC(DLMGCP, LOGL_NOTICE, "none");
 | 
				
			||||||
@@ -601,7 +601,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		payload_types[0] = payload_type;
 | 
							payload_types[0] = payload_type;
 | 
				
			||||||
		if (mgcp_conn_rtp_is_osmux(conn))
 | 
							if (mgcp_conn_rtp_is_osmux(conn))
 | 
				
			||||||
			local_port = endp->trunk->cfg->osmux.local_port;
 | 
								local_port = endp->trunk->cfg->osmux_port;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			local_port = conn->end.local_port;
 | 
								local_port = conn->end.local_port;
 | 
				
			||||||
		rc = add_audio(sdp, payload_types, 1, local_port);
 | 
							rc = add_audio(sdp, payload_types, 1, local_port);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ __attribute__((no_sanitize("undefined")))
 | 
				
			|||||||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
					void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_rtp_state *state = &conn->state;
 | 
						struct mgcp_rtp_state *state = &conn->state;
 | 
				
			||||||
	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*expected = state->stats.cycles + state->stats.max_seq;
 | 
						*expected = state->stats.cycles + state->stats.max_seq;
 | 
				
			||||||
	*expected = *expected - state->stats.base_seq + 1;
 | 
						*expected = *expected - state->stats.base_seq + 1;
 | 
				
			||||||
@@ -80,10 +80,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	int ploss;
 | 
						int ploss;
 | 
				
			||||||
	int nchars;
 | 
						int nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
						struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
 | 
						struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
 | 
						struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
 | 
						struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	calc_loss(conn, &expected, &ploss);
 | 
						calc_loss(conn, &expected, &ploss);
 | 
				
			||||||
	jitter = calc_jitter(&conn->state);
 | 
						jitter = calc_jitter(&conn->state);
 | 
				
			||||||
@@ -99,7 +99,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
	str += nchars;
 | 
						str += nchars;
 | 
				
			||||||
	str_len -= nchars;
 | 
						str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn->conn->endp->trunk->cfg->osmux.usage != OSMUX_USAGE_OFF) {
 | 
						if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
 | 
				
			||||||
		/* Error Counter */
 | 
							/* Error Counter */
 | 
				
			||||||
		nchars = snprintf(str, str_len,
 | 
							nchars = snprintf(str, str_len,
 | 
				
			||||||
				  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
									  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
 | 
				
			||||||
@@ -112,12 +112,9 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
 | 
				
			|||||||
		str_len -= nchars;
 | 
							str_len -= nchars;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
							if (conn->osmux.state == OSMUX_STATE_ENABLED) {
 | 
				
			||||||
			struct rate_ctr *osmux_chunks_rx, *osmux_octets_rx;
 | 
					 | 
				
			||||||
			osmux_chunks_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
					 | 
				
			||||||
			osmux_octets_rx = rate_ctr_group_get_ctr(conn->ctrg, OSMUX_OCTETS_RX_CTR);
 | 
					 | 
				
			||||||
			snprintf(str, str_len,
 | 
								snprintf(str, str_len,
 | 
				
			||||||
				 "\r\nX-Osmux-ST: CR=%" PRIu64 ", BR=%" PRIu64,
 | 
									 "\r\nX-Osmux-ST: CR=%u, BR=%u",
 | 
				
			||||||
				 osmux_chunks_rx->current, osmux_octets_rx->current);
 | 
									 conn->osmux.stats.chunks, conn->osmux.stats.octets);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,207 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 | 
					 | 
				
			||||||
 * All Rights Reserved
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Author: Eric Wild
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU Affero General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU Affero General Public License
 | 
					 | 
				
			||||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <inttypes.h>
 | 
					 | 
				
			||||||
#include <stdatomic.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <sys/eventfd.h>
 | 
					 | 
				
			||||||
#include <sys/types.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <talloc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <osmocom/mgcp/mgcp_threads_queue.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
classic lamport circular lockfree spsc queue:
 | 
					 | 
				
			||||||
every "side" only writes its own ptr, but may read the other sides ptr
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
notify reader using eventfd as soon as element is added, reader then reads until
 | 
					 | 
				
			||||||
read fails
 | 
					 | 
				
			||||||
-> reader pops in a loop until FALSE and might get spurious events because it
 | 
					 | 
				
			||||||
read before it was notified, which is fine
 | 
					 | 
				
			||||||
-> writing pushes *the same data* in a loop until TRUE, blocks
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
shutting this down requires
 | 
					 | 
				
			||||||
1) to stop reading and pushing
 | 
					 | 
				
			||||||
2) ONE side to take care of the eventfds
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct spsc *spsc_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr, bool blockw)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct spsc *q = talloc_zero_size(talloc_ctx, sizeof(struct spsc) + sizeof(uintptr_t) * count);
 | 
					 | 
				
			||||||
	atomic_init(&q->readptr, 0);
 | 
					 | 
				
			||||||
	atomic_init(&q->writeptr, 0);
 | 
					 | 
				
			||||||
	q->efd_r = eventfd(0, blockr ? 0 : EFD_NONBLOCK);
 | 
					 | 
				
			||||||
	q->efd_w = eventfd(1, blockw ? 0 : EFD_NONBLOCK);
 | 
					 | 
				
			||||||
	q->count = count;
 | 
					 | 
				
			||||||
	q->size_per_buf = size_per_buf;
 | 
					 | 
				
			||||||
	q->buf = talloc_zero_size(q, size_per_buf * count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (int i = 0; i < count; i++)
 | 
					 | 
				
			||||||
		q->data[i] = (uintptr_t)q->buf + i * size_per_buf;
 | 
					 | 
				
			||||||
	return q;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void spsc_deinit(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	talloc_free(q->buf);
 | 
					 | 
				
			||||||
	close(q->efd_r);
 | 
					 | 
				
			||||||
	close(q->efd_w);
 | 
					 | 
				
			||||||
	talloc_free(q);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t spsc_check_r(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	uint64_t efdr;
 | 
					 | 
				
			||||||
	return read(q->efd_r, &efdr, sizeof(uint64_t));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static ssize_t spsc_check_w(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	uint64_t efdr;
 | 
					 | 
				
			||||||
	return read(q->efd_w, &efdr, sizeof(uint64_t));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static void spsc_notify_r(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	uint64_t efdu = 1;
 | 
					 | 
				
			||||||
	write(q->efd_r, &efdu, sizeof(uint64_t));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static void spsc_notify_w(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	uint64_t efdu = 1;
 | 
					 | 
				
			||||||
	write(q->efd_w, &efdu, sizeof(uint64_t));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Adds element to the queue by copying the data.
 | 
					 | 
				
			||||||
 *  \param[in] q queue.
 | 
					 | 
				
			||||||
 *  \param[in] elem input buffer, must match the originally configured queue buffer size!.
 | 
					 | 
				
			||||||
 *  \returns true if queue was not full and element was successfully pushed */
 | 
					 | 
				
			||||||
bool spsc_push(struct spsc *q, void *elem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t cur_wp, cur_rp;
 | 
					 | 
				
			||||||
	cur_wp = atomic_load_explicit(&q->writeptr, memory_order_relaxed);
 | 
					 | 
				
			||||||
	cur_rp = atomic_load_explicit(&q->readptr, memory_order_acquire);
 | 
					 | 
				
			||||||
	if ((cur_wp + 1) % q->count == cur_rp) {
 | 
					 | 
				
			||||||
		spsc_check_w(q); /* blocks, ensures next (!) call succeeds */
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	memcpy((void *)q->data[cur_wp], elem, q->size_per_buf);
 | 
					 | 
				
			||||||
	atomic_store_explicit(&q->writeptr, (cur_wp + 1) % q->count, memory_order_release);
 | 
					 | 
				
			||||||
	spsc_notify_r(q); /* fine after release */
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Reads the read-fd of the queue, which, depending on settings passed on queue creation, blocks.
 | 
					 | 
				
			||||||
 * This function can be used to deliberately wait for a non-empty queue on the read side.
 | 
					 | 
				
			||||||
 *  \param[in] q queue.
 | 
					 | 
				
			||||||
 *  \returns result of reading the fd. */
 | 
					 | 
				
			||||||
ssize_t spsc_prep_pop(struct spsc *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return spsc_check_r(q);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Removes element from the queue by copying the data.
 | 
					 | 
				
			||||||
 *  \param[in] q queue.
 | 
					 | 
				
			||||||
 *  \param[in] elem output buffer, must match the originally configured queue buffer size!.
 | 
					 | 
				
			||||||
 *  \returns true if queue was not empty and element was successfully removed */
 | 
					 | 
				
			||||||
bool spsc_pop(struct spsc *q, void *elem)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t cur_wp, cur_rp;
 | 
					 | 
				
			||||||
	cur_wp = atomic_load_explicit(&q->writeptr, memory_order_acquire);
 | 
					 | 
				
			||||||
	cur_rp = atomic_load_explicit(&q->readptr, memory_order_relaxed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (cur_wp == cur_rp) /* blocks via prep_pop */
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	memcpy(elem, (void *)q->data[cur_rp], q->size_per_buf);
 | 
					 | 
				
			||||||
	atomic_store_explicit(&q->readptr, (cur_rp + 1) % q->count, memory_order_release);
 | 
					 | 
				
			||||||
	spsc_notify_w(q);
 | 
					 | 
				
			||||||
	return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Creates a bidirectional queue channel that consists of two queues, one in each direction,
 | 
					 | 
				
			||||||
 *  commonly referred to as a and b side.
 | 
					 | 
				
			||||||
 *  \param[in] talloc_ctx allocation context.
 | 
					 | 
				
			||||||
 *  \param[in] count number of buffers per queue.
 | 
					 | 
				
			||||||
 *  \param[in] size_per_buf size of buffers per queue.
 | 
					 | 
				
			||||||
 *  \param[in] blockr_a should reading the a-side read fd block?.
 | 
					 | 
				
			||||||
 *  \param[in] blockw_a should reading the a-side write fd block?.
 | 
					 | 
				
			||||||
 *  \param[in] blockr_b should reading the b-side read fd block?.
 | 
					 | 
				
			||||||
 *  \param[in] blockw_b should reading the b-side write fd block?.
 | 
					 | 
				
			||||||
  *  \returns queue channel */
 | 
					 | 
				
			||||||
struct qchan spsc_chan_init_ex(void *talloc_ctx, unsigned int count, unsigned int size_per_buf, bool blockr_a,
 | 
					 | 
				
			||||||
			       bool blockw_a, bool blockr_b, bool blockw_b)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct qchan q;
 | 
					 | 
				
			||||||
	q.a = spsc_init(talloc_ctx, count, size_per_buf, blockr_a, blockw_a);
 | 
					 | 
				
			||||||
	q.b = spsc_init(talloc_ctx, count, size_per_buf, blockr_b, blockw_b);
 | 
					 | 
				
			||||||
	return q;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Creates a bidirectional queue channel that consists of two queues, one in each direction,
 | 
					 | 
				
			||||||
 *  commonly referred to as a and b side.
 | 
					 | 
				
			||||||
 *  \param[in] talloc_ctx allocation context.
 | 
					 | 
				
			||||||
 *  \param[in] count number of buffers per queue.
 | 
					 | 
				
			||||||
 *  \param[in] size_per_buf size of buffers per queue.
 | 
					 | 
				
			||||||
 *  \returns queue channel */
 | 
					 | 
				
			||||||
struct qchan spsc_chan_init(void *talloc_ctx, unsigned int count, unsigned int size_per_buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return spsc_chan_init_ex(talloc_ctx, count, size_per_buf, false, true, false, true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Closes a bidirectional queue channel.
 | 
					 | 
				
			||||||
 *  \param[in] q queue */
 | 
					 | 
				
			||||||
void spsc_chan_close(struct qchan *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	spsc_deinit(q->a);
 | 
					 | 
				
			||||||
	spsc_deinit(q->b);
 | 
					 | 
				
			||||||
	free(q);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
					 | 
				
			||||||
 *  \param[in] q queue channel.
 | 
					 | 
				
			||||||
 *  \returns fd */
 | 
					 | 
				
			||||||
int spsc_get_a_rdfd(struct qchan *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return q->a->efd_r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
					 | 
				
			||||||
 *  \param[in] q queue channel.
 | 
					 | 
				
			||||||
 *  \returns fd */
 | 
					 | 
				
			||||||
int spsc_get_b_rdfd(struct qchan *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return q->b->efd_r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
					 | 
				
			||||||
 *  \param[in] q queue channel.
 | 
					 | 
				
			||||||
 *  \returns fd */
 | 
					 | 
				
			||||||
int spsc_get_a_wrfd(struct qchan *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return q->a->efd_w;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
/*! Gets queue channel read/write fd for a/b side according to function name.
 | 
					 | 
				
			||||||
 *  \param[in] q queue channel.
 | 
					 | 
				
			||||||
 *  \returns fd */
 | 
					 | 
				
			||||||
int spsc_get_b_wrfd(struct qchan *q)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return q->b->efd_w;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -129,7 +129,7 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
							vty_out(vty, " rtp force-ptime %d%s", g_cfg->force_ptime,
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (g_cfg->osmux.usage) {
 | 
						switch (g_cfg->osmux) {
 | 
				
			||||||
	case OSMUX_USAGE_ON:
 | 
						case OSMUX_USAGE_ON:
 | 
				
			||||||
		vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux on%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
@@ -141,23 +141,17 @@ static int config_write_mgcp(struct vty *vty)
 | 
				
			|||||||
		vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
							vty_out(vty, " osmux off%s", VTY_NEWLINE);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (g_cfg->osmux.usage != OSMUX_USAGE_OFF) {
 | 
						if (g_cfg->osmux) {
 | 
				
			||||||
		if (g_cfg->osmux.local_addr_v4)
 | 
					 | 
				
			||||||
		vty_out(vty, " osmux bind-ip %s%s",
 | 
							vty_out(vty, " osmux bind-ip %s%s",
 | 
				
			||||||
				g_cfg->osmux.local_addr_v4, VTY_NEWLINE);
 | 
								g_cfg->osmux_addr, VTY_NEWLINE);
 | 
				
			||||||
		if (g_cfg->osmux.local_addr_v6)
 | 
					 | 
				
			||||||
			vty_out(vty, " osmux bind-ip-v6 %s%s",
 | 
					 | 
				
			||||||
				g_cfg->osmux.local_addr_v6, VTY_NEWLINE);
 | 
					 | 
				
			||||||
		vty_out(vty, " osmux batch-factor %d%s",
 | 
							vty_out(vty, " osmux batch-factor %d%s",
 | 
				
			||||||
			g_cfg->osmux.batch_factor, VTY_NEWLINE);
 | 
								g_cfg->osmux_batch, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux batch-size %u%s",
 | 
							vty_out(vty, " osmux batch-size %u%s",
 | 
				
			||||||
			g_cfg->osmux.batch_size, VTY_NEWLINE);
 | 
								g_cfg->osmux_batch_size, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux port %u%s",
 | 
							vty_out(vty, " osmux port %u%s",
 | 
				
			||||||
			g_cfg->osmux.local_port, VTY_NEWLINE);
 | 
								g_cfg->osmux_port, VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux dummy %s%s",
 | 
							vty_out(vty, " osmux dummy %s%s",
 | 
				
			||||||
			g_cfg->osmux.dummy_padding ? "on" : "off", VTY_NEWLINE);
 | 
								g_cfg->osmux_dummy ? "on" : "off", VTY_NEWLINE);
 | 
				
			||||||
		vty_out(vty, " osmux peer-behind-nat %s%s",
 | 
					 | 
				
			||||||
			g_cfg->osmux.peer_behind_nat ? "on" : "off", VTY_NEWLINE);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->conn_timeout)
 | 
						if (g_cfg->conn_timeout)
 | 
				
			||||||
@@ -175,11 +169,11 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
	struct rate_ctr *rx_packets, *rx_bytes;
 | 
						struct rate_ctr *rx_packets, *rx_bytes;
 | 
				
			||||||
	struct rate_ctr *dropped_packets;
 | 
						struct rate_ctr *dropped_packets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_TX_CTR);
 | 
						tx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
 | 
				
			||||||
	tx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_TX_CTR);
 | 
						tx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
 | 
				
			||||||
	rx_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
						rx_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
	rx_bytes = rate_ctr_group_get_ctr(conn->ctrg, RTP_OCTETS_RX_CTR);
 | 
						rx_bytes = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
 | 
				
			||||||
	dropped_packets = rate_ctr_group_get_ctr(conn->ctrg, RTP_DROPPED_PACKETS_CTR);
 | 
						dropped_packets = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_DROPPED_PACKETS_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty,
 | 
						vty_out(vty,
 | 
				
			||||||
		"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
							"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
				
			||||||
@@ -203,30 +197,6 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn)
 | 
				
			|||||||
		VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
							VTY_NEWLINE, end->fmtp_extra, codec->audio_name,
 | 
				
			||||||
		codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
							codec->subtype_name, VTY_NEWLINE, end->output_enabled,
 | 
				
			||||||
		end->force_output_ptime, VTY_NEWLINE);
 | 
							end->force_output_ptime, VTY_NEWLINE);
 | 
				
			||||||
	if (mgcp_conn_rtp_is_osmux(conn)) {
 | 
					 | 
				
			||||||
		struct rate_ctr *rx_chunks, *rx_octets, *rtp_tx, *rtp_tx_dropped, *octets_tx;
 | 
					 | 
				
			||||||
		rx_chunks = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_CHUNKS_RX_CTR);
 | 
					 | 
				
			||||||
		rx_octets = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_OCTETS_RX_CTR);
 | 
					 | 
				
			||||||
		rtp_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_CTR);
 | 
					 | 
				
			||||||
		rtp_tx_dropped =  rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_RTP_PACKETS_TX_DROPPED_CTR);
 | 
					 | 
				
			||||||
		octets_tx = rate_ctr_group_get_ctr(conn->osmux.ctrg, OSMUX_AMR_OCTETS_TX_CTR);
 | 
					 | 
				
			||||||
		vty_out(vty,
 | 
					 | 
				
			||||||
		"   Osmux:%s"
 | 
					 | 
				
			||||||
		"    State: %s%s"
 | 
					 | 
				
			||||||
		"    Local CID: %d%s"
 | 
					 | 
				
			||||||
		"    Remote CID: %d%s"
 | 
					 | 
				
			||||||
		"    Chunks received: %" PRIu64 " (%" PRIu64 " bytes total)%s"
 | 
					 | 
				
			||||||
		"    RTP Packets encoded (Tx): %" PRIu64 " (%" PRIu64 " AMR octets total)%s"
 | 
					 | 
				
			||||||
		"    AMR payloads Dropped (Tx): %" PRIu64 "%s",
 | 
					 | 
				
			||||||
		VTY_NEWLINE, osmux_state_str(conn->osmux.state), VTY_NEWLINE,
 | 
					 | 
				
			||||||
		conn->osmux.local_cid_allocated ? conn->osmux.local_cid : -1, VTY_NEWLINE,
 | 
					 | 
				
			||||||
		conn->osmux.remote_cid_present ? conn->osmux.remote_cid : -1, VTY_NEWLINE,
 | 
					 | 
				
			||||||
		rx_chunks->current, rx_octets->current, VTY_NEWLINE,
 | 
					 | 
				
			||||||
		rtp_tx->current, octets_tx->current, VTY_NEWLINE,
 | 
					 | 
				
			||||||
		rtp_tx_dropped->current, VTY_NEWLINE
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
					static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp,
 | 
				
			||||||
@@ -319,14 +289,6 @@ static void dump_ratectr_trunk(struct vty *vty, struct mgcp_trunk *trunk)
 | 
				
			|||||||
					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
										   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
				
			||||||
					   ratectr->all_rtp_conn_stats);
 | 
										   ratectr->all_rtp_conn_stats);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ratectr->all_osmux_conn_stats) {
 | 
					 | 
				
			||||||
		vty_out(vty, "   %s:%s",
 | 
					 | 
				
			||||||
			ratectr->all_osmux_conn_stats->desc->group_description,
 | 
					 | 
				
			||||||
			VTY_NEWLINE);
 | 
					 | 
				
			||||||
		vty_out_rate_ctr_group_fmt(vty,
 | 
					 | 
				
			||||||
					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 | 
					 | 
				
			||||||
					   ratectr->all_osmux_conn_stats);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
						if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
 | 
				
			||||||
		vty_out(vty, "   %s:%s",
 | 
							vty_out(vty, "   %s:%s",
 | 
				
			||||||
@@ -380,7 +342,7 @@ static int mgcp_show(struct vty *vty, int argc, const char **argv,
 | 
				
			|||||||
	llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
						llist_for_each_entry(trunk, &g_cfg->trunks, entry)
 | 
				
			||||||
		dump_trunk(vty, trunk, show_stats, active_only);
 | 
							dump_trunk(vty, trunk, show_stats, active_only);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_cfg->osmux.usage != OSMUX_USAGE_OFF)
 | 
						if (g_cfg->osmux)
 | 
				
			||||||
		vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
							vty_out(vty, "Osmux used CID: %d%s", osmux_cid_pool_count_used(),
 | 
				
			||||||
			VTY_NEWLINE);
 | 
								VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1577,12 +1539,12 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
	OSMO_ASSERT(trunk);
 | 
						OSMO_ASSERT(trunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcmp(argv[0], "off") == 0) {
 | 
						if (strcmp(argv[0], "off") == 0) {
 | 
				
			||||||
		g_cfg->osmux.usage = OSMUX_USAGE_OFF;
 | 
							g_cfg->osmux = OSMUX_USAGE_OFF;
 | 
				
			||||||
		return CMD_SUCCESS;
 | 
							return CMD_SUCCESS;
 | 
				
			||||||
	} else if (strcmp(argv[0], "on") == 0)
 | 
						} else if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux.usage = 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.usage = OSMUX_USAGE_ONLY;
 | 
							g_cfg->osmux = OSMUX_USAGE_ONLY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1590,29 +1552,12 @@ DEFUN(cfg_mgcp_osmux,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_ip,
 | 
					DEFUN(cfg_mgcp_osmux_ip,
 | 
				
			||||||
      cfg_mgcp_osmux_ip_cmd,
 | 
					      cfg_mgcp_osmux_ip_cmd,
 | 
				
			||||||
      "osmux bind-ip " VTY_IPV4_CMD,
 | 
					      "osmux bind-ip " VTY_IPV46_CMD,
 | 
				
			||||||
      OSMUX_STR IP_STR
 | 
					 | 
				
			||||||
      "IPv4 Address to bind to\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v4, argv[0]);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_ip_v6,
 | 
					 | 
				
			||||||
      cfg_mgcp_osmux_ip_v6_cmd,
 | 
					 | 
				
			||||||
      "osmux bind-ip-v6 " VTY_IPV6_CMD,
 | 
					 | 
				
			||||||
      OSMUX_STR IP_STR
 | 
					      OSMUX_STR IP_STR
 | 
				
			||||||
 | 
					      "IPv4 Address to bind to\n"
 | 
				
			||||||
      "IPv6 Address to bind to\n")
 | 
					      "IPv6 Address to bind to\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	osmo_talloc_replace_string(g_cfg, &g_cfg->osmux.local_addr_v6, argv[0]);
 | 
						osmo_strlcpy(g_cfg->osmux_addr, argv[0], sizeof(g_cfg->osmux_addr));
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_port,
 | 
					 | 
				
			||||||
      cfg_mgcp_osmux_port_cmd,
 | 
					 | 
				
			||||||
      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	g_cfg->osmux.local_port = atoi(argv[0]);
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1621,7 +1566,7 @@ DEFUN(cfg_mgcp_osmux_batch_factor,
 | 
				
			|||||||
      "osmux batch-factor <1-8>",
 | 
					      "osmux batch-factor <1-8>",
 | 
				
			||||||
      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
					      OSMUX_STR "Batching factor\n" "Number of messages in the batch\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux.batch_factor = atoi(argv[0]);
 | 
						g_cfg->osmux_batch = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1630,7 +1575,15 @@ DEFUN(cfg_mgcp_osmux_batch_size,
 | 
				
			|||||||
      "osmux batch-size <1-65535>",
 | 
					      "osmux batch-size <1-65535>",
 | 
				
			||||||
      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
					      OSMUX_STR "batch size\n" "Batch size in bytes\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	g_cfg->osmux.batch_size = atoi(argv[0]);
 | 
						g_cfg->osmux_batch_size = atoi(argv[0]);
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_mgcp_osmux_port,
 | 
				
			||||||
 | 
					      cfg_mgcp_osmux_port_cmd,
 | 
				
			||||||
 | 
					      "osmux port <1-65535>", OSMUX_STR "port\n" "UDP port\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						g_cfg->osmux_port = atoi(argv[0]);
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1641,24 +1594,9 @@ DEFUN(cfg_mgcp_osmux_dummy,
 | 
				
			|||||||
      "Disable dummy padding\n")
 | 
					      "Disable dummy padding\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (strcmp(argv[0], "on") == 0)
 | 
						if (strcmp(argv[0], "on") == 0)
 | 
				
			||||||
		g_cfg->osmux.dummy_padding = true;
 | 
							g_cfg->osmux_dummy = 1;
 | 
				
			||||||
	else if (strcmp(argv[0], "off") == 0)
 | 
						else if (strcmp(argv[0], "off") == 0)
 | 
				
			||||||
		g_cfg->osmux.dummy_padding = false;
 | 
							g_cfg->osmux_dummy = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFUN(cfg_mgcp_osmux_peer_behind_nat,
 | 
					 | 
				
			||||||
      cfg_mgcp_osmux_peer_behind_nat_cmd,
 | 
					 | 
				
			||||||
      "osmux peer-behind-nat (on|off)",
 | 
					 | 
				
			||||||
      OSMUX_STR "Define whether peer is behind NAT\n"
 | 
					 | 
				
			||||||
      "Peer is behind NAT\n"
 | 
					 | 
				
			||||||
      "Peer is NOT behind NAT\n")
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (strcmp(argv[0], "on") == 0)
 | 
					 | 
				
			||||||
		g_cfg->osmux.peer_behind_nat = true;
 | 
					 | 
				
			||||||
	else if (strcmp(argv[0], "off") == 0)
 | 
					 | 
				
			||||||
		g_cfg->osmux.peer_behind_nat = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1748,12 +1686,10 @@ int mgcp_vty_init(void)
 | 
				
			|||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_sdp_payload_send_name_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_ip_v6_cmd);
 | 
					 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
					 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_factor_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_batch_size_cmd);
 | 
				
			||||||
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_port_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_osmux_dummy_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_osmux_peer_behind_nat_cmd);
 | 
					 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_no_allow_transcoding_cmd);
 | 
				
			||||||
	install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
						install_element(MGCP_NODE, &cfg_mgcp_domain_cmd);
 | 
				
			||||||
@@ -1798,9 +1734,9 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	struct mgcp_trunk *trunk;
 | 
						struct mgcp_trunk *trunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->osmux.local_port = OSMUX_DEFAULT_PORT;
 | 
						cfg->osmux_port = OSMUX_PORT;
 | 
				
			||||||
	cfg->osmux.batch_factor = 4;
 | 
						cfg->osmux_batch = 4;
 | 
				
			||||||
	cfg->osmux.batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
						cfg->osmux_batch_size = OSMUX_BATCH_DEFAULT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_cfg = cfg;
 | 
						g_cfg = cfg;
 | 
				
			||||||
	rc = vty_read_config_file(config_file, NULL);
 | 
						rc = vty_read_config_file(config_file, NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@
 | 
				
			|||||||
#include <osmocom/mgcp/debug.h>
 | 
					#include <osmocom/mgcp/debug.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_endp.h>
 | 
					#include <osmocom/mgcp/mgcp_endp.h>
 | 
				
			||||||
#include <osmocom/mgcp/mgcp_trunk.h>
 | 
					#include <osmocom/mgcp/mgcp_trunk.h>
 | 
				
			||||||
 | 
					#include <osmocom/mgcp/mgcp_ctrl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/application.h>
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
@@ -50,7 +51,7 @@
 | 
				
			|||||||
#include <osmocom/core/rate_ctr.h>
 | 
					#include <osmocom/core/rate_ctr.h>
 | 
				
			||||||
#include <osmocom/core/logging.h>
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
#include <osmocom/core/socket.h>
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
#include <osmocom/ctrl/control_if.h>
 | 
					
 | 
				
			||||||
#include <osmocom/ctrl/control_vty.h>
 | 
					#include <osmocom/ctrl/control_vty.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/telnet_interface.h>
 | 
					#include <osmocom/vty/telnet_interface.h>
 | 
				
			||||||
@@ -94,7 +95,7 @@ static char *config_file = "osmo-mgw.cfg";
 | 
				
			|||||||
/* used by msgb and mgcp */
 | 
					/* used by msgb and mgcp */
 | 
				
			||||||
void *tall_mgw_ctx = NULL;
 | 
					void *tall_mgw_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_help(void)
 | 
					static void print_help()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	printf("Some useful options:\n");
 | 
						printf("Some useful options:\n");
 | 
				
			||||||
	printf(" -h --help is printing this text.\n");
 | 
						printf(" -h --help is printing this text.\n");
 | 
				
			||||||
@@ -294,22 +295,13 @@ static const struct log_info_cat log_categories[] = {
 | 
				
			|||||||
		  .name = "DRTP",
 | 
							  .name = "DRTP",
 | 
				
			||||||
		  .description = "RTP stream handling",
 | 
							  .description = "RTP stream handling",
 | 
				
			||||||
		  .color = "\033[1;30m",
 | 
							  .color = "\033[1;30m",
 | 
				
			||||||
		  .enabled = 1,
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
		  .loglevel = LOGL_NOTICE,
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	[DE1] = {
 | 
						[DE1] = {
 | 
				
			||||||
		  .name = "DE1",
 | 
							  .name = "DE1",
 | 
				
			||||||
		  .description = "E1 line handling",
 | 
							  .description = "E1 line handling",
 | 
				
			||||||
		  .color = "\033[1;31m",
 | 
							  .color = "\033[1;31m",
 | 
				
			||||||
		  .enabled = 1,
 | 
							  .enabled = 1,.loglevel = LOGL_NOTICE,
 | 
				
			||||||
		  .loglevel = LOGL_NOTICE,
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	[DOSMUX] = {
 | 
					 | 
				
			||||||
		  .name = "DOSMUX",
 | 
					 | 
				
			||||||
		  .description = "Osmux (Osmocom RTP multiplexing)",
 | 
					 | 
				
			||||||
		  .color = "\033[1;32m",
 | 
					 | 
				
			||||||
		  .enabled = 1,
 | 
					 | 
				
			||||||
		  .loglevel = LOGL_NOTICE,
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -365,7 +357,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cfg->ctrl = ctrl_interface_setup(cfg, OSMO_CTRL_PORT_MGW, NULL);
 | 
						cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
				
			||||||
	if (!cfg->ctrl) {
 | 
						if (!cfg->ctrl) {
 | 
				
			||||||
		fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
							fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
 | 
				
			||||||
			ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
								ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ EXTRA_DIST = \
 | 
				
			|||||||
	mgcp_test.ok \
 | 
						mgcp_test.ok \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check_PROGRAMS = \
 | 
					noinst_PROGRAMS = \
 | 
				
			||||||
	mgcp_test \
 | 
						mgcp_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -868,7 +868,7 @@ static void test_messages(void)
 | 
				
			|||||||
					printf("Connection mode not set\n");
 | 
										printf("Connection mode not set\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				OSMO_ASSERT(conn->end.output_enabled
 | 
									OSMO_ASSERT(conn->end.output_enabled
 | 
				
			||||||
					    == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
 | 
										    == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				conn->conn->mode |= CONN_UNMODIFIED;
 | 
									conn->conn->mode |= CONN_UNMODIFIED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1071,7 +1071,7 @@ static void test_packet_loss_calc(void)
 | 
				
			|||||||
				    "test-connection");
 | 
									    "test-connection");
 | 
				
			||||||
		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
							conn = mgcp_conn_get_rtp(&endp, _conn->id);
 | 
				
			||||||
		state = &conn->state;
 | 
							state = &conn->state;
 | 
				
			||||||
		packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
 | 
							packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->stats.initialized = 1;
 | 
							state->stats.initialized = 1;
 | 
				
			||||||
		state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
							state->stats.base_seq = pl_test_dat[i].base_seq;
 | 
				
			||||||
@@ -1492,7 +1492,7 @@ static void test_multilple_codec(void)
 | 
				
			|||||||
	conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
						conn = mgcp_conn_get_rtp(endp, conn_id);
 | 
				
			||||||
	OSMO_ASSERT(conn);
 | 
						OSMO_ASSERT(conn);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
						OSMO_ASSERT(conn->end.codec->payload_type == 3);
 | 
				
			||||||
	OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
 | 
						OSMO_ASSERT(conn->end.rtp_port == htons(16434));
 | 
				
			||||||
	memset(&addr, 0, sizeof(addr));
 | 
						memset(&addr, 0, sizeof(addr));
 | 
				
			||||||
	inet_aton("8.8.8.8", &addr);
 | 
						inet_aton("8.8.8.8", &addr);
 | 
				
			||||||
	OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
 | 
						OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
 | 
				
			||||||
@@ -1632,8 +1632,7 @@ static void test_osmux_cid(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 256; ++i) {
 | 
						for (i = 0; i < 256; ++i) {
 | 
				
			||||||
		id = osmux_cid_pool_get_next();
 | 
							id = osmux_cid_pool_get_next();
 | 
				
			||||||
		/* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
 | 
							OSMO_ASSERT(id == i);
 | 
				
			||||||
		OSMO_ASSERT(id == ((i + 1) & 0xff));
 | 
					 | 
				
			||||||
		OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
 | 
							OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1897,13 +1896,16 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
 | 
									{ 121, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
								{ .payload_type_map = {111, 121}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -1912,13 +1914,15 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
									{ 122, "AMR/8000", &amr_param_octet_aligned_unset, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
								{ .payload_type_map = {111, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -1927,13 +1931,15 @@ static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translat
 | 
				
			|||||||
		.codecs = {
 | 
							.codecs = {
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
									{ 111, "AMR/8000", &amr_param_octet_aligned_true, },
 | 
				
			||||||
 | 
									{ 112, "AMR/8000", &amr_param_octet_aligned_false, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				{ 122, "AMR/8000", NULL, },
 | 
									{ 122, "AMR/8000", NULL, },
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.expect = {
 | 
							.expect = {
 | 
				
			||||||
			{ .payload_type_map = {111, 122}, },
 | 
								{ .payload_type_map = {111, -EINVAL}, },
 | 
				
			||||||
 | 
								{ .payload_type_map = {112, 122} },
 | 
				
			||||||
			{ .end = true },
 | 
								{ .end = true },
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
@@ -2079,7 +2085,7 @@ static void test_mgcp_codec_pt_translate(void)
 | 
				
			|||||||
	OSMO_ASSERT(ok);
 | 
						OSMO_ASSERT(ok);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_conn_id_matching(void)
 | 
					void test_conn_id_matching()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mgcp_endpoint endp = {};
 | 
						struct mgcp_endpoint endp = {};
 | 
				
			||||||
	struct mgcp_conn *conn;
 | 
						struct mgcp_conn *conn;
 | 
				
			||||||
@@ -2119,7 +2125,7 @@ void test_conn_id_matching(void)
 | 
				
			|||||||
	talloc_free(conn);
 | 
						talloc_free(conn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_e1_trunk_nr_from_epname(void)
 | 
					void test_e1_trunk_nr_from_epname()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int trunk_nr;
 | 
						unsigned int trunk_nr;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -2169,7 +2175,7 @@ void test_e1_trunk_nr_from_epname(void)
 | 
				
			|||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_mgcp_is_rtp_dummy_payload(void)
 | 
					void test_mgcp_is_rtp_dummy_payload()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* realistic rtp packet */
 | 
						/* realistic rtp packet */
 | 
				
			||||||
	static const char rtp_payload[] =
 | 
						static const char rtp_payload[] =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1347,24 +1347,32 @@ Testing mgcp_codec_pt_translate()
 | 
				
			|||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 | 
					#4: conn1 has no codecs
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
				
			||||||
    0: 112 AMR/8000/1 octet-aligned=1  -> rc=0
 | 
					    1:   0 PCMU/8000/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, 0) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
#5: test AMR with differing octet-aligned settings
 | 
					#5: test AMR with differing octet-aligned settings
 | 
				
			||||||
 | 
					 - add codecs on conn0:
 | 
				
			||||||
    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - add codecs on conn1:
 | 
				
			||||||
#5: test AMR with differing octet-aligned settings
 | 
					    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(conn0, conn1, 111) -> 121
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
 | 
					 - mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
					 - 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)
 | 
					#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
				
			||||||
 - add codecs on conn0:
 | 
					 - add codecs on conn0:
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn1, conn0, 122) -> 111
 | 
					    0: 111 AMR/8000 octet-aligned=1  -> rc=0
 | 
				
			||||||
#6: test AMR with missing octet-aligned settings (defaults to 0)
 | 
					    1: 112 AMR/8000 octet-aligned=0  -> rc=0
 | 
				
			||||||
 | 
					 - add codecs on conn1:
 | 
				
			||||||
    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
					    0: 122 AMR/8000 octet-aligned=unset  -> rc=0
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
 | 
				
			||||||
 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
					 - mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ EXTRA_DIST = \
 | 
				
			|||||||
	mgcp_client_test.err \
 | 
						mgcp_client_test.err \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check_PROGRAMS = \
 | 
					noinst_PROGRAMS = \
 | 
				
			||||||
	mgcp_client_test \
 | 
						mgcp_client_test \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -315,7 +315,7 @@ void test_mgcp_msg(void)
 | 
				
			|||||||
	msgb_free(msg);
 | 
						msgb_free(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_mgcp_client_cancel(void)
 | 
					void test_mgcp_client_cancel()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mgcp_trans_id_t trans_id;
 | 
						mgcp_trans_id_t trans_id;
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
@@ -487,7 +487,7 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void test_sdp_section_start(void)
 | 
					void test_sdp_section_start()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	int failures = 0;
 | 
						int failures = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user