mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 13:03:33 +00:00
Compare commits
9 Commits
1.9.2
...
neels/35c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bebcef4844 | ||
|
|
f174dd641d | ||
|
|
3ed3eb8e0f | ||
|
|
fdc5f111aa | ||
|
|
02d612a926 | ||
|
|
944af2f641 | ||
|
|
f2a65b8bbb | ||
|
|
332308d994 | ||
|
|
099332824e |
563
.clang-format
563
.clang-format
@@ -1,563 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# clang-format configuration file. Intended for clang-format >= 4.
|
||||
#
|
||||
# For more information, see:
|
||||
#
|
||||
# Documentation/process/clang-format.rst
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
#
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
#AfterExternBlock: false # Unknown to clang-format-5.0
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
#SplitEmptyFunction: true # Unknown to clang-format-4.0
|
||||
#SplitEmptyRecord: true # Unknown to clang-format-4.0
|
||||
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
#CompactNamespaces: false # Unknown to clang-format-4.0
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
#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
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
||||
ObjCBlockIndentWidth: 8
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
|
||||
# Taken from git's rules
|
||||
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
#SortUsingDeclarations: false # Unknown to clang-format-4.0
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
|
||||
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
|
||||
SpaceBeforeParens: ControlStatements
|
||||
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp03
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
||||
...
|
||||
45
.gitignore
vendored
45
.gitignore
vendored
@@ -2,13 +2,20 @@ debian/*.log
|
||||
*.o
|
||||
*.lo
|
||||
*.a
|
||||
*.la
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
bscconfig.h
|
||||
bscconfig.h.in
|
||||
src/osmo-mgw/osmo-mgw
|
||||
openbsc.pc
|
||||
src/osmo-nitb/osmo-nitb
|
||||
src/osmo-bsc_mgcp/osmo-bsc_mgcp
|
||||
src/osmo-bsc/osmo-bsc
|
||||
src/utils/meas_vis
|
||||
src/utils/meas_json
|
||||
src/utils/osmo-meas-pcap2db
|
||||
src/utils/osmo-meas-udp2db
|
||||
src/utils/smpp_mirror
|
||||
*.*~
|
||||
*.sw?
|
||||
.libs
|
||||
@@ -16,7 +23,6 @@ src/osmo-mgw/osmo-mgw
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.pc
|
||||
*~
|
||||
|
||||
#configure
|
||||
aclocal.m4
|
||||
@@ -40,9 +46,32 @@ m4/*.m4
|
||||
.version
|
||||
|
||||
|
||||
# apps and app data
|
||||
hlr.sqlite3
|
||||
src/utils/bs11_config
|
||||
src/ipaccess/ipaccess-config
|
||||
src/ipaccess/abisip-find
|
||||
src/ipaccess/ipaccess-firmware
|
||||
src/ipaccess/ipaccess-proxy
|
||||
src/utils/isdnsync
|
||||
src/nat/bsc_nat
|
||||
src/gprs/osmo-sgsn
|
||||
src/gprs/osmo-gbproxy
|
||||
src/gprs/osmo-gtphub
|
||||
src/osmo-bsc_nat/osmo-bsc_nat
|
||||
src/libcommon/gsup_test_client
|
||||
src/osmo-msc/osmo-msc
|
||||
|
||||
#tests
|
||||
tests/testsuite.dir
|
||||
tests/*/*_test
|
||||
# ignore compiled binaries like msc_vlr_test_foo; do not ignore
|
||||
# msc_vlr_test_foo.{c,ok,err}, but do still ignore the corresponding .o object
|
||||
# files:
|
||||
tests/msc_vlr/msc_vlr_test_*
|
||||
!tests/msc_vlr/msc_vlr_test_*.*
|
||||
tests/msc_vlr/msc_vlr_test_*.o
|
||||
|
||||
|
||||
tests/atconfig
|
||||
tests/atlocal
|
||||
@@ -50,7 +79,10 @@ tests/package.m4
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
|
||||
gsn_restart
|
||||
src/openbsc.cfg*
|
||||
writtenconfig/
|
||||
gtphub_restart_count
|
||||
|
||||
# manuals
|
||||
doc/manuals/*.html
|
||||
@@ -62,10 +94,3 @@ doc/manuals/generated/
|
||||
doc/manuals/osmomsc-usermanual.xml
|
||||
doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
contrib/osmo-mgw.spec
|
||||
|
||||
#vs code
|
||||
.cache
|
||||
.vscode
|
||||
|
||||
|
||||
10
Makefile.am
10
Makefile.am
@@ -9,10 +9,10 @@ AM_CPPFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
SUBDIRS = \
|
||||
doc \
|
||||
include \
|
||||
src \
|
||||
tests \
|
||||
doc \
|
||||
contrib \
|
||||
$(NULL)
|
||||
|
||||
@@ -22,13 +22,7 @@ pkgconfig_DATA = \
|
||||
$(NULL)
|
||||
|
||||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-mgw.spec.in \
|
||||
debian \
|
||||
git-version-gen \
|
||||
osmoappdesc.py \
|
||||
$(NULL)
|
||||
EXTRA_DIST = git-version-gen osmoappdesc.py .version
|
||||
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||
|
||||
@@ -24,3 +24,4 @@
|
||||
# If any interfaces have been removed or changed since the last public release, a=0.
|
||||
#
|
||||
#library what description / commit summary line
|
||||
libosmo-mgcp-client various Drop legacy API functions and mgcp_client_conf members
|
||||
|
||||
51
configure.ac
51
configure.ac
@@ -9,8 +9,6 @@ AC_CONFIG_AUX_DIR([.])
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
|
||||
CFLAGS="$CFLAGS -std=gnu11"
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
@@ -24,11 +22,6 @@ AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
LT_INIT
|
||||
|
||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
||||
AS_CASE(["$LD"],[*clang*],
|
||||
[AS_CASE(["${host_os}"],
|
||||
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
|
||||
|
||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||
@@ -36,24 +29,20 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||
fi
|
||||
PKG_PROG_PKG_CONFIG([0.20])
|
||||
|
||||
dnl check for AX_CHECK_COMPILE_FLAG
|
||||
m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
|
||||
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
|
||||
])
|
||||
|
||||
dnl checks for libraries
|
||||
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
|
||||
AC_SUBST(LIBRARY_DL)
|
||||
|
||||
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
|
||||
AC_SUBST(LIBRARY_DLSYM)
|
||||
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.2.0)
|
||||
|
||||
CFLAGS="$CFLAGS -pthread"
|
||||
LDFLAGS="$LDFLAGS -pthread"
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.12.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.12.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.12.0)
|
||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.3.0)
|
||||
|
||||
AC_ARG_ENABLE(sanitize,
|
||||
[AS_HELP_STRING(
|
||||
@@ -85,6 +74,26 @@ then
|
||||
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
|
||||
fi
|
||||
|
||||
dnl Checks for typedefs, structures and compiler characteristics
|
||||
|
||||
# The following test is taken from WebKit's webkit.m4
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -fvisibility=hidden "
|
||||
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
|
||||
[ AC_MSG_RESULT([yes])
|
||||
SYMBOL_VISIBILITY="-fvisibility=hidden"],
|
||||
AC_MSG_RESULT([no]))
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
AC_SUBST(SYMBOL_VISIBILITY)
|
||||
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=null-dereference], [CFLAGS="$CFLAGS -Werror=null-dereference"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
|
||||
|
||||
# Coverage build taken from WebKit's configure.in
|
||||
AC_MSG_CHECKING([whether to enable code coverage support])
|
||||
AC_ARG_ENABLE(coverage,
|
||||
@@ -197,10 +206,10 @@ AC_OUTPUT(
|
||||
tests/atlocal
|
||||
tests/mgcp_client/Makefile
|
||||
tests/mgcp/Makefile
|
||||
tests/iuup/Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/osmo-mgw.spec
|
||||
Makefile)
|
||||
|
||||
@@ -36,6 +36,7 @@ osmo-build-dep.sh libosmo-netif
|
||||
# Additional configure options and depends
|
||||
CONFIG=""
|
||||
if [ "$WITH_MANUALS" = "1" ]; then
|
||||
osmo-build-dep.sh osmo-gsm-manuals
|
||||
CONFIG="--enable-manuals"
|
||||
fi
|
||||
|
||||
@@ -49,18 +50,17 @@ set -x
|
||||
|
||||
cd "$base"
|
||||
autoreconf --install --force
|
||||
./configure --enable-sanitize --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
|
||||
./configure --enable-vty-tests --enable-external-tests --enable-werror $CONFIG
|
||||
$MAKE $PARALLEL_MAKE
|
||||
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|
||||
|| cat-testlogs.sh
|
||||
LD_LIBRARY_PATH="$inst/lib" \
|
||||
DISTCHECK_CONFIGURE_FLAGS="--enable-vty-tests --enable-external-tests $CONFIG" \
|
||||
$MAKE $PARALLEL_MAKE distcheck \
|
||||
$MAKE distcheck \
|
||||
|| cat-testlogs.sh
|
||||
|
||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
#
|
||||
# spec file for package osmo-mgw
|
||||
#
|
||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
# Please submit bugfixes or comments via http://bugs.opensuse.org/
|
||||
#
|
||||
|
||||
Name: osmo-mgw
|
||||
Version: @VERSION@
|
||||
Release: 0
|
||||
Summary: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
||||
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
||||
Group: Hardware/Mobile
|
||||
URL: https://osmocom.org/projects/osmo-mgw
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
BuildRequires: automake >= 1.9
|
||||
BuildRequires: libtool >= 2
|
||||
BuildRequires: pkgconfig >= 0.20
|
||||
%if 0%{?suse_version}
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.6.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.6.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.6.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.6.0
|
||||
BuildRequires: pkgconfig(libosmocoding) >= 1.6.0
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.2.0
|
||||
BuildRequires: pkgconfig(libosmotrau) >= 1.2.0
|
||||
%{?systemd_requires}
|
||||
|
||||
%description
|
||||
OsmoMGW is Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks.
|
||||
|
||||
%package -n libosmo-mgcp-client9
|
||||
Summary: Osmocom's Media Gateway Control Protocol client library
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-mgcp-client9
|
||||
Osmocom's Media Gateway Control Protocol client library.
|
||||
|
||||
%package -n libosmo-mgcp-client-devel
|
||||
Summary: Development files for Osmocom's Media Gateway Control Protocol client library
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: libosmo-mgcp-client9 = %{version}
|
||||
|
||||
%description -n libosmo-mgcp-client-devel
|
||||
Osmocom's Media Gateway Control Protocol client librarary.
|
||||
|
||||
This subpackage contains libraries and header files for developing
|
||||
applications that want to make use of libosmo-mgcp-client.
|
||||
|
||||
%package -n libosmo-mgcp-devel
|
||||
Summary: Development files for Osmocom's Media Gateway server library
|
||||
Group: Development/Libraries/C and C++
|
||||
|
||||
%description -n libosmo-mgcp-devel
|
||||
Osmocom's Media Gateway Control Protocol server library.
|
||||
|
||||
This subpackage contains libraries and header files for developing
|
||||
applications that want to make use of libosmo-mgcp.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
echo "%{version}" >.tarball-version
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
--disable-static \
|
||||
--docdir=%{_docdir}/%{name} \
|
||||
--with-systemdsystemunitdir=%{_unitdir}
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
%make_install
|
||||
find %{buildroot} -type f -name "*.la" -delete -print
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||
|
||||
%post -n libosmo-mgcp-client9 -p /sbin/ldconfig
|
||||
%postun -n libosmo-mgcp-client9 -p /sbin/ldconfig
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%preun
|
||||
%service_del_preun osmo-mgw.service
|
||||
|
||||
%postun
|
||||
%service_del_postun osmo-mgw.service
|
||||
|
||||
%pre
|
||||
%service_add_pre osmo-mgw.service
|
||||
|
||||
%post
|
||||
%service_add_post osmo-mgw.service
|
||||
%endif
|
||||
|
||||
%files
|
||||
%license COPYING
|
||||
%doc AUTHORS README
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%dir %{_docdir}/%{name}/examples/osmo-mgw
|
||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
|
||||
%{_bindir}/osmo-mgw
|
||||
%{_unitdir}/osmo-mgw.service
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-mgw.cfg
|
||||
|
||||
%files -n libosmo-mgcp-client9
|
||||
%{_libdir}/libosmo-mgcp-client.so.9*
|
||||
|
||||
%files -n libosmo-mgcp-client-devel
|
||||
%{_libdir}/libosmo-mgcp-client.so
|
||||
%{_libdir}/pkgconfig/libosmo-mgcp-client.pc
|
||||
%dir %{_includedir}/osmocom
|
||||
%dir %{_includedir}/osmocom/mgcp_client
|
||||
%{_includedir}/osmocom/mgcp_client/*.h
|
||||
|
||||
%files -n libosmo-mgcp-devel
|
||||
%dir %{_includedir}/osmocom
|
||||
%dir %{_includedir}/osmocom/mgcp
|
||||
%{_includedir}/osmocom/mgcp/*.h
|
||||
|
||||
%changelog
|
||||
@@ -1,13 +1,12 @@
|
||||
[Unit]
|
||||
Description=Osmocom Media Gateway (MGW)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
|
||||
RestartSec=2
|
||||
ExecStopPost=/usr/local/bin/save_log_tail osmo-mgw
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
548
debian/changelog
vendored
548
debian/changelog
vendored
@@ -1,551 +1,3 @@
|
||||
osmo-mgw (1.9.2) unstable; urgency=medium
|
||||
|
||||
* systemd: depend on networking-online.target
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Fri, 26 May 2023 14:57:36 +0200
|
||||
|
||||
osmo-mgw (1.9.1) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* libosmo-mgcp: e1: fix memleaks in e1_recv_cb()
|
||||
|
||||
-- Harald Welte <laforge@osmocom.org> Mon, 18 Apr 2022 10:58:50 +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
|
||||
|
||||
* attempt to fix RPM spec file after recent soversion bump
|
||||
|
||||
-- Harald Welte <laforge@osmocom.org> Wed, 24 Feb 2021 10:56:17 +0100
|
||||
|
||||
osmo-mgw (1.8.0) unstable; urgency=medium
|
||||
|
||||
[ Harald Welte ]
|
||||
* Fix number of endpoints of default trunk
|
||||
* Add CTRL interface to osmo-mgw
|
||||
* Update per-trunk global packet/byte counters in real-time
|
||||
* remove accidential TODO-RELEASE entry
|
||||
* mgcp_protocol: Avoid code duplication between virtual + other trunks
|
||||
* osmo-mgw.spec.in: Use %config(noreplace) to retain current config file
|
||||
* mgcp_client_init(): consider "talloc returns NULL" case
|
||||
* mgcp_client_pending_add(): Consider "talloc returns NULL" case
|
||||
* libosmo-mgcp-client: fix memleak in case if no response is received
|
||||
* debian/control + SPEC: Add missing build dependency to libosmo-abis
|
||||
* osmo-mgw.spec.in: Fix dependency to libosmoabis
|
||||
* osmo-mgw.spec.in: Add missing dependency to libosmotrau
|
||||
* Add example osmo-mgw configuration file for Abis/E1
|
||||
* use osmo_fd_setup() whenever applicable
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix vty dump_trunk: start from zero, do not omit first CONN
|
||||
* allow larger MGCP client wqueue: 10 -> 1024
|
||||
* add osmo-mgw --vty-ref-xml: dump VTY ref XML to stdout
|
||||
* manuals: generate vty reference xml at build time
|
||||
* refactor: use msgb to receive, pass and send RTP packets
|
||||
* change timer T2427001 to X2427
|
||||
|
||||
[ Philipp Maier ]
|
||||
* doc: do not bind osmo-mgw to random ip-address
|
||||
* cosmetic: remove excess newlines
|
||||
* mgcp: remove unused callback pointer
|
||||
* mgcp: find better locations for LOGPCONN and LOGPENDP
|
||||
* vty: fix unreachable code (error msg on trunk alloc fail)
|
||||
* mgcp_vty: fix indentation
|
||||
* osmo-mgw: rename struct mgcp_trunk_config and symbol tcfg
|
||||
* mgcp_vty: fix indentation in VTY config write
|
||||
* osmo-mgw: refactor endpoint and trunk handling
|
||||
* mgcp_trunk: remove audio_name and audio_payload
|
||||
* ratectr: move rate counter definitions into mgcp_ratectr.h
|
||||
* cosmetic: fix doxygen
|
||||
* cosmetic: fix doxygen
|
||||
* cosmetic: fix doxygen for mgcp_cleanup_rtp_bridge_cb()
|
||||
* trunk: get rid of virt_trunk pointer
|
||||
* cosmetic: remove excess space
|
||||
* endp: move endpoint name generation into mgcp_endp.c
|
||||
* endp: add name generator function for E1 endpoints
|
||||
* mgcp_client: add docstring for mgcp_client_rtpbridge_wildcard()
|
||||
* mgcp_trunk: fix docstring for mgcp_trunk_alloc()
|
||||
* mgcp_osmux: remove unused define constants
|
||||
* mgcp_trunk: move enum mgcp_trunk_type to mgcp_trunk.h
|
||||
* mgcp_trunk: use enum type for trunk type variable
|
||||
* trunk: parse E1 trunk number
|
||||
* endp: add typeset for e1-endpoints
|
||||
* mgcp_conn: move struct mgcp_conn mgcp_conn.h
|
||||
* mgcp_internal: remove forward declaration struct mgcp_endpoint_type
|
||||
* endp: add E1 endpoint interlocking
|
||||
* endp: require domain name also for E1 endpoints
|
||||
* mgcp_trunk: pick trunk by number and type
|
||||
* mgcp_client: add function to generate e1-endpoint names
|
||||
* mgcp_endp: use define constant to define max number of E1 subslots
|
||||
* mgcp_endp.c: cosmetic: fix sourcecode formatting
|
||||
* mgcp_trunk: remove double check
|
||||
* mgcp_test: do not access endpoint array elements directly
|
||||
* mgcp_vty: fix endpoint number configuration
|
||||
* mgcp_test: remove trunk2 from unit-test
|
||||
* mgcp_trunk: use talloc_zero_array instead of _talloc_zero_array
|
||||
* mgcp_protocol: remove unused variable
|
||||
* mgcp_e1: finish E1 support, add E1 support from libosmoabis
|
||||
* get rid of mgcp_internal.h
|
||||
* mgcp_ratectr: fix comments in header file
|
||||
* mgcp_e1: use return value of e1inp_line_update()
|
||||
* mgcp_protocol: log when endpoint is unavailable
|
||||
* cosmetic: add missing new-line
|
||||
* mgcp_trunk: drop "trunk 0" limitation
|
||||
* mgcp_e1: make E1 ts initalization more debugable
|
||||
* mgcp_e1: remove unused struct member trunk->e1.line
|
||||
* mgcp_endp: use NUM_E1_TS from e1_input.h
|
||||
* mgcp_trunk: increase default number of virtual endpoints
|
||||
* cosmetic: mgcp_client_fsm: change error message.
|
||||
* mgcp_vty: remove remains of loopback functionality
|
||||
* mgcp_vty: deprecate bind early command
|
||||
* mgcp_e1: do not expose function mgcp_e1_init()
|
||||
* mgcp_vty: add user attributes to configuration commands
|
||||
* overview: update section limitations.
|
||||
* overview: fix graph "OsmoMGW used with OsmoBSC"
|
||||
* overview: fix graph "OsmoMGW used with OsmoMSC"
|
||||
* overview: add graph to show E1 integration
|
||||
* configuration: remove hint towards trunk 0 limit
|
||||
* configuration: drop note about lackin E1 support
|
||||
* configuration: add note that changes to trunks need a restart
|
||||
* mgcp_vty: fix config write for trunk 0
|
||||
* mgcp_vty: add missing VTY commands for E1 trunks
|
||||
* mgcp_trunk: get rid of magic numbers for E1 slots
|
||||
* configuration: add section about E1 trunks
|
||||
* usermanual: add chapter about mgcp endpoints
|
||||
* mgcp_client: get rid of magic numbers for E1 slots
|
||||
|
||||
[ Eric ]
|
||||
* tests: dlopen does not imply availability of dlsym..
|
||||
* configure.ac: fix libtool issue with clang and sanitizer
|
||||
|
||||
[ Alexander Chemeris ]
|
||||
* vty: Prepend VTY output of counters for better visual separation.
|
||||
* counters: Implement more useful counters.
|
||||
* mgcp_network: Fix a typo in the comment bahviour -> behaviour
|
||||
* rtp_bridge: Demote a chatty ERROR log message to DEBUG level.
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Use OSMO_FD_* instead of deprecated BSC_FD_*
|
||||
* Support setting rt-prio and cpu-affinity mask through VTY
|
||||
* cosmetic: Rename main talloc ctx
|
||||
* mgcp-client: Support IPv6 in osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr() implementation
|
||||
* mgcp-client: Fix trailing whitespace in mgcp_client_fsm.h
|
||||
* mgcp_client: Use INET6_ADDRSTRLEN to store addresses in str format
|
||||
* mgcp_client: Allow submitting and parsing IPv6 addr in SDP
|
||||
* mgcp_client: Allow setting IPv6 addresses
|
||||
* mgcp_client: Make MGCP_CLIENT_LOCAL_ADDR_DEFAULT IPv6 compatible
|
||||
* mgcp_client: Support validating IPv6 addresses in CRCX and MDCX commands
|
||||
* mgcp_client: Deprecate unused IPv4-only API
|
||||
* mgcp_client: copy back Connection Information from MDCX ACK
|
||||
* mgw: Fix mgcp_rtp_end field description comment
|
||||
* mgw: Initial IPv6 support
|
||||
* mgw: Introduce VTY cmd 'rtp bind-ip-v6' command
|
||||
* mgw: Find and store RTP conn local_addr once during CRCX handling
|
||||
* mgw: Announce and rebind new local address if change required during MDCX
|
||||
* mgw: osmux: Avoid sending packets on recvonly connection
|
||||
* mgw: Release endpoint after last conn times out
|
||||
* mgw: osmux: Fix conn watchdog timeout not updated
|
||||
* mgw: Don't be case-sensitive when parsing X-Osmo-IGN param
|
||||
* cosmetic: Fix typo in comment
|
||||
* mgw: Avoid logging notice message each time we receive nt param in LCO
|
||||
* mgw: Fix return value documentation for API mgcp_verify_call_id
|
||||
* cosmetic: Fix typo in comment
|
||||
* contrib/jenkins: Enable parallel make in make distcheck
|
||||
* .gitignore: Ignore new autofoo tmp files
|
||||
* tests: Replace deprecated API log_set_print_filename
|
||||
|
||||
[ Oliver Smith ]
|
||||
* contrib: import RPM spec
|
||||
* contrib: integrate RPM spec
|
||||
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
|
||||
* contrib/jenkins: don't build osmo-gsm-manuals
|
||||
* configure.ac: set -std=gnu11
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* libosmo-mgcp-client: fix use-after-free in mgcp_client_tx()
|
||||
* libosmo-mgcp-client: fix use-after-free in mgcp_msg_gen()
|
||||
* libosmo-mgcp: fix unsigned compared against 0 in mgcp_trunk_by_name()
|
||||
* libosmo-mgcp: fix unused extra argument to printf() in add_fmtp()
|
||||
* libosmo-mgcp: always check result of msgb_printf() in add_fmtp()
|
||||
* libosmo-mgcp-client: mgcp_client_tx(): return rc on error
|
||||
* debian/control: change maintainer to the Osmocom team / mailing list
|
||||
* vty: use install_lib_element() and install_lib_element_ve()
|
||||
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
|
||||
* fixup mgcp_trunk: increase default number of virtual endpoints
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* configure.ac: require libosmoabis + libosmotrau >= 1.0.0
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 18:28:45 +0100
|
||||
|
||||
osmo-mgw (1.7.0) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* rename codecs_cmp() to codecs_same()
|
||||
* mgcp_codec: constify 'param' arg
|
||||
* fix crashes: don't assert on incoming RTP packet size
|
||||
* mgcp_send(): stop looping on conversion error
|
||||
* mgcp_codec: split codec_free() off of codec_init()
|
||||
* fix memleak: actually free strings in mgcp_codec_reset_all()
|
||||
* mgcp_test: extend / rewrite test_mgcp_codec_pt_translate()
|
||||
* test_mgcp_codec_pt_translate(): more tests
|
||||
* differentiate AMR octet-aligned=0 vs =1
|
||||
* ptmap: implicitly match '/8000' and '/8000/1'
|
||||
* mgcp_codec: codec_set(): log about all possible errors
|
||||
* mgcp_codec_add: fix audio_name size check
|
||||
* explicitly free codecs in mgcp_rtp_conn_cleanup()
|
||||
* tweak mgcp_parse_audio_ptime_rtpmap()
|
||||
* SDP: store all ptmap entries
|
||||
* mgcp_client_fsm cleanup: Do not assert on DLCX failure
|
||||
* clear pending requests on MGCP failure
|
||||
* client: endp fsm: add notify struct, prep for cancel-notify
|
||||
* client: endp fsm: clear ci[] before dispatching DLCX success
|
||||
* client: endp fsm: allow cancelling a notify event
|
||||
* client: endp fsm: add osmo_mgcpc_ep_ci_ep()
|
||||
* accept MGCP without SDP
|
||||
* fix use-after-free: require new fsm deferred dealloc, check for term
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mgcp_test: Correctly release all endpoints allocated
|
||||
* mgw: Allocate mgcp_conn instance under tcfg->endpoints
|
||||
|
||||
[ Harald Welte ]
|
||||
* manual: Fix copy+paste error
|
||||
* mgcp_client: Check for osmo_fsm_register() error return value
|
||||
* Move fsm_mgcp_client regstration to __attribute__((contructor))
|
||||
* exit(2) on unsupported positional arguments on command line
|
||||
|
||||
[ Oliver Smith ]
|
||||
* osmoappdesc.py: switch to python 3
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 13:35:09 +0100
|
||||
|
||||
osmo-mgw (1.6.0) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* Cosmetic: fix spaces/tabs in mgcp_requests[]
|
||||
* Inactive connection cleanup (disabled by default)
|
||||
* debian: create -doc subpackage with pdf manuals
|
||||
* vty: allow 0 as conn-timeout to disable it
|
||||
* vty: update desc of conn-timeout
|
||||
* manuals: update VTY documentation
|
||||
* "make dist" fix for: no rule to make mgcp_common.h
|
||||
* contrib/jenkins.sh: run "make maintainer-clean"
|
||||
|
||||
[ Philipp Maier ]
|
||||
* Add option to GSM HR frames to RFC5593 representation
|
||||
* mgcp_sdp: cosmetic: correct typo in comment
|
||||
* mgco_client: cosmetic: remove excess whitespace
|
||||
* mgcp_sdp: mgcp_sdp.c does not include own header file
|
||||
* mgcp_sdp: untangle parsing of a= parameters
|
||||
* mgcp_network: use mgcp_rtp_codec in downlink format callback
|
||||
* AMR: Add function to convert between bw-effient and octet aligned mode
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* log: don't spam with "can not patch PT" messages
|
||||
* mgcp client: allow setting conn mode for CRCX and MDCX
|
||||
* make codec_table public as osmo_mgcpc_codec_names
|
||||
* move MGW endpoint FSM from osmo-bsc to here
|
||||
* fix: multiple initial CRCX
|
||||
* constify map_codec_to_pt() ptmap arg
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mgcp-client: whitespace cleanup in mgcp_client.c
|
||||
* mgcp-client: Sanitize implementation of mgcp_client_rtpbridge_wildcard
|
||||
* libosmo-mgcp: Use trunk type during endpoint allocation
|
||||
* cosmetic: Fix typos in comment
|
||||
* cosmetic: tests: mgcp_client_test: clean trailing whitespace
|
||||
* mgcp_msg: Log faulty line on Osmux parsing error
|
||||
* cosmetic: handle_modify_con: Fix indentation level
|
||||
* Introduce log fmt helpers LOGPENDP and LOGPCONN
|
||||
* create_response_with_sdp: Fix inclusion of X-Osmux
|
||||
* osmux: Cleanup of CID alloc pool APIs
|
||||
* mgcp_osmux.c: osmux_enable_endpoint: Fix incorrect return check
|
||||
* osmux: Log osmux socket during osmux_init
|
||||
* mgcp-cli: Change osmo_mgcpc_ep_fsm name to avoid collision with old osmo-bsc
|
||||
* osmux: Document func and return different rc upon osmux init failure
|
||||
* osmux: Fix reception of legacy dummy payloads
|
||||
* osmux: Use LOGPCONN in several log calls
|
||||
* cosmetic: mgcp_udp_send: Document port param is in network byte order
|
||||
* cosmetic: osmux: Document network byte order in port variable
|
||||
* vty: Allow enabling Osmux
|
||||
* osmux: Allocate CID during CRCX
|
||||
* osmux: Introduce mgcp_conn_rtp_is_osmux() helper
|
||||
* osmux: Mark conn_rtp->type as osmux during CRCX
|
||||
* mgcp-cli: Allow submitting X-Osmux on CRCX request
|
||||
* mgcp-cli: Parse X-Osmux on CRCX response
|
||||
* osmux: Handle Osmux MGCP extension in MDCX messages
|
||||
* mgcp-cli: Allow submitting X-Osmux on MDCX request
|
||||
* mgcp-cli: Parse X-Osmux on MDCX response
|
||||
* osmux: Drop unneeded OSMUX_STATE_NEGOTIATING
|
||||
* mgcp-cli: endpoint_fsm: Add API to retrieve Osmux CID from MGW
|
||||
* osmux: Provide correct local port during mgcp resp
|
||||
* osmux: Use remote port to send osmux frames
|
||||
* osmux: Improve logging around osmux enabling events
|
||||
* osmux: Delay osmux enable of conn until remote addr is configured by MDCX
|
||||
* osmux: Redo read/write osmux glue code to have data routed correctly
|
||||
* mgw, mgcp-li: Handle X-Osmux param name as case insensitive
|
||||
* osmux: Use DUMMY ft msg as per Osmux spec
|
||||
* osmux: Fix loopback for Osmux connections
|
||||
* osmux: Fix CID release for non-enabled connections
|
||||
* osmux: Fix hardcoded rtp payload_type 98 in osmux conn
|
||||
* mgcp-cli: Validate osmux cid value during mgcp_msg_gen
|
||||
* mgw: Support uppercase LCO options
|
||||
* mgw: Support lowercase header parameters
|
||||
* mgcp-cli: Support lowercase header parameters
|
||||
* mgw: Support receiving uppercase connection mode
|
||||
* mgw: Support receiving lowercase LCO codec
|
||||
* mgw: Make check of duplicated LCO fields case insensitive
|
||||
* mgw: Allow receiving lowercase MGCP header keyword
|
||||
* mgw: Allow receiving lowercase X-Osmo-Ign Callid field
|
||||
* mgw: Allow receiving uppercase noanswer keyword
|
||||
* doc: X-Osmo-IGN: small formatting and typo fixes
|
||||
* doc: Add Osmux documentation to OsmoMGW User Manual
|
||||
* Catch unsigned integer MGCP parsing errors with strtoul
|
||||
* Fix return variable of strtoul()
|
||||
* Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
|
||||
* configure.ac: Require libosmo-netif 0.6.0
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* mgcp_internal: LOGPENDP: ensure *endp is not NULL
|
||||
|
||||
[ Harald Welte ]
|
||||
* handle NULL return of rate_ctr_group_alloc()
|
||||
* update .gitignore
|
||||
* mgcp_sdp: Don't check if an unsigned int is below 0
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* configure.ac: drop useless check for -fvisibility=hidden
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* manuals: Add script to regenerate vty/counter documentation
|
||||
* manuals: Update vty/counter documentation
|
||||
|
||||
[ Hoernchen ]
|
||||
* turn -Werror=null-dereference into a warning
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 16:52:58 +0200
|
||||
|
||||
osmo-mgw (1.5.0) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* gitignore: Filter *.pc
|
||||
* configure: Find correct libgsm's gsm.h header
|
||||
* vty: Fix typo writing bts-jitter-buffer-delay-{min,max}
|
||||
* Remove libosmo-legacy-mgcp and osmo-bsc-mgcp
|
||||
* debian: Remove dangling symlink to osmo-bsc-mgcp.service
|
||||
* Install systemd services with autotools
|
||||
* Install sample cfg file to /etc/osmocom
|
||||
* mgcp: Fix osmux_cid_bitmap static array size calculation
|
||||
* mgcp_osmux: Use define to calculate rtp_ssrc_winlen
|
||||
* osmux: Avoid initing output without enabling osmux
|
||||
* mgcp: Log endpoint nr consistently as hex
|
||||
* osmux_send_dummy: Avoid logging incorrectly and sending if osmux not enabled
|
||||
* osmux: Don't process regular osmux frames if disabled by cfg
|
||||
* osmux: Move parse_cid of legacy dummy frames to own function
|
||||
* osmux: Make func handling dummy frames independent of endp type
|
||||
* osmux: allow enabling osmux only on correct activating state
|
||||
* osmux: Improve checks around activating and using enabled osmux
|
||||
* osmux.h: Document enum osmux_state
|
||||
* osmux: Avoid processing further frames if conn not found
|
||||
|
||||
[ Philipp Maier ]
|
||||
* mgcp_client_fsm: allow ptmap in mgcp_client_fsm as well
|
||||
* mgcp_network: translate payload type numbers in RTP packets
|
||||
* mgcp_client: use IETF source port as for MGCP
|
||||
* mgcp_client: increment local port number when port is in use
|
||||
* mgcp_test: release endpoints after use
|
||||
* network: do not patch PT of RTCP packets
|
||||
* network: check packets before further processing
|
||||
* Cosmetic: remove misplaced line break
|
||||
* mgcp_sdp: restructure mgcp_write_response_sdp() (rtpmap)
|
||||
* mgcp_sdp: restructure mgcp_write_response_sdp() (audio)
|
||||
* mgcp_client: check local port only once
|
||||
* mgcp_client_fsm: switch to MGCP_CONN_RECV_SEND in add_audio()
|
||||
* mgcp_protocol: increase buffer space for codec name in LCO
|
||||
* osmo-mgw: Add vty reference manual
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix handling of "Wrong domain name" error
|
||||
* interpret domain '*' as 'allow any domain'
|
||||
* cosmetic: log: fix "CallIDs does not match"
|
||||
* fix 3G hack: allow any IP for loopback and 0.0.0.0
|
||||
* cosmetic: drop code dup in mgcp_client_fsm.c CRCX
|
||||
* add X-Osmo-IGN MGCP header to ignore CallID
|
||||
* X-Osmo-IGN: rather parse items by token, not char
|
||||
* mgcp_test: fix log of conn_id presence
|
||||
* mgcp_test: fix get_conn_id_from_response() CI length
|
||||
* mgcp_client_test: cosmetically re-arrange reply_to() args
|
||||
* mgcp_client_test: use "\r\n\r\n" instead of "\n\n"
|
||||
* mgcp_client_test: also verify received conn_id
|
||||
* mgcp_client_test: test long conn_id
|
||||
* mgcp_client: error on too long conn id
|
||||
* mgcp_common: rename to MGCP_CONN_ID_MAXLEN
|
||||
* doc: fix mgcp_verify_ci() return val doc
|
||||
* mgcp_verify_ci(): return meaningful error codes
|
||||
* fix mgcp_verify_ci(): off-by-one in max len check
|
||||
* generate shorter 'I:' conn IDs
|
||||
* mgcp_conn_get(): compare conn Id ('I:') case insensitively
|
||||
* mgcp_conn_get(): match conn Id ('I:') despite leading zeros
|
||||
* cosmetic: mgcp_test: fix get_conn_id_from_response()
|
||||
* comment: indicate struct type for mgcp_endpoint.conns
|
||||
* log: avoid logging early media as error
|
||||
* fix osmo-mgw -s; fixes osmo-mgw.service using -s
|
||||
* Importing history from osmo-gsm-manuals.git
|
||||
* OsmoMGW: update VTY reference
|
||||
* OsmoMGW: document the 'X-Osmo-IGN' MGCP extension
|
||||
* mgw: update vty reference
|
||||
* drop/replace very weird logging in mgcp_client.c
|
||||
* check_rtp: on IP:port errors, log the IP and port
|
||||
* osmo-mgw: err-log: include expected domain name
|
||||
* mgcp_client_vty: fix missing talloc_free
|
||||
* mgcp_client: drop a bunch of dead code
|
||||
* mgcp_client: logging tweaks
|
||||
* mgcp_client: make domain part of endpoint configurable
|
||||
* mgcp_client: tweak some log levels INFO -> {DEBUG,ERROR}
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* add VTY commands which show specific mgcp endpoints
|
||||
* add MGCP CRCX command statistics to osmo-mgw
|
||||
* show RTP TX/RX stats in 'mgcp show stats' output
|
||||
* use local variable for rate counters in handle_create_con()
|
||||
* add more mgcp crxc error counters
|
||||
* add MDCX command statistics to osmo-mgw
|
||||
* add aggregated rtp connection stats to osmo-mgw
|
||||
* add DLCX command statistics to osmo-mgw
|
||||
|
||||
[ Harald Welte ]
|
||||
* debian/rules: Don't overwrite .tarball-version
|
||||
* check_rtp_origin(): Don't memcmp sockadd_in and in_addr
|
||||
* check_rtp_origin(): Avoid using memcmp for comparing integer types
|
||||
* vty-ref: Update URI of docbook 5.0 schema
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* mgw: Add new VTY reference
|
||||
* Add initial OsmoMGW manual
|
||||
|
||||
[ Oliver Smith ]
|
||||
* build manuals moved here from osmo-gsm-manuals.git
|
||||
* jenkins.sh: remove leftover MGCP env variable
|
||||
* Fix DISTCHECK_CONFIGURE_FLAGS override
|
||||
* contrib/jenkins.sh: build and publish manuals
|
||||
* contrib: fix makedistcheck with disabled systemd
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Sun, 20 Jan 2019 15:02:18 +0100
|
||||
|
||||
osmo-mgw (1.4.0) unstable; urgency=medium
|
||||
|
||||
[ Philipp Maier ]
|
||||
|
||||
21
debian/control
vendored
21
debian/control
vendored
@@ -1,15 +1,13 @@
|
||||
Source: osmo-mgw
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Maintainer: Alexander Couzens <lynxis@fe80.eu>
|
||||
Build-Depends: debhelper (>=9),
|
||||
dh-autoreconf,
|
||||
pkg-config,
|
||||
autotools-dev,
|
||||
libosmocore-dev (>= 1.6.0),
|
||||
libosmo-netif-dev (>= 1.1.0),
|
||||
libosmo-abis-dev (>= 1.2.0),
|
||||
osmo-gsm-manuals-dev (>= 1.2.0)
|
||||
libosmocore-dev,
|
||||
libosmo-netif-dev
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Git: git://git.osmocom.org/osmo-mgw.git
|
||||
Vcs-Browser: https://git.osmocom.org/osmo-mgw/
|
||||
@@ -21,7 +19,7 @@ Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
|
||||
|
||||
Package: libosmo-mgcp-client9
|
||||
Package: libosmo-mgcp-client3
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
@@ -33,14 +31,5 @@ Package: libosmo-mgcp-client-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: libosmo-mgcp-client9 (= ${binary:Version}), ${misc:Depends}
|
||||
Depends: libosmo-mgcp-client3 (= ${binary:Version}), ${misc:Depends}
|
||||
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
|
||||
|
||||
Package: osmo-mgw-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
Priority: optional
|
||||
Depends: ${misc:Depends}
|
||||
Description: ${misc:Package} PDF documentation
|
||||
Various manuals: user manual, VTY reference manual and/or
|
||||
protocol/interface manuals.
|
||||
|
||||
1
debian/osmo-mgw-doc.install
vendored
1
debian/osmo-mgw-doc.install
vendored
@@ -1 +0,0 @@
|
||||
usr/share/doc/osmo-mgw-doc/*.pdf
|
||||
1
debian/osmo-mgw.install
vendored
1
debian/osmo-mgw.install
vendored
@@ -2,4 +2,3 @@ etc/osmocom/osmo-mgw.cfg
|
||||
lib/systemd/system/osmo-mgw.service
|
||||
usr/bin/osmo-mgw
|
||||
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw.cfg
|
||||
usr/share/doc/osmo-mgw/examples/osmo-mgw/osmo-mgw-abis_e1.cfg
|
||||
|
||||
6
debian/rules
vendored
6
debian/rules
vendored
@@ -30,10 +30,6 @@ override_dh_auto_test:
|
||||
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
|
||||
|
||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
|
||||
override_dh_compress:
|
||||
dh_compress -X.pdf
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
|
||||
|
||||
# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
!
|
||||
! MGCP configuration example
|
||||
!
|
||||
e1_input
|
||||
e1_line 0 driver dahdi
|
||||
e1_line 0 port 0
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 512
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
rtp-patch ssrc
|
||||
rtp-patch timestamp
|
||||
trunk 1
|
||||
rtp keep-alive once
|
||||
no rtp keep-alive
|
||||
line 0
|
||||
@@ -4,13 +4,13 @@
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp port-range 4002 16000
|
||||
rtp bind-ip 127.0.0.1
|
||||
rtp bind-ip 10.9.1.122
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
rtp ip-tos 184
|
||||
bind port 2427
|
||||
sdp audio payload number 98
|
||||
sdp audio payload name GSM
|
||||
number endpoints 512
|
||||
number endpoints 31
|
||||
loop 0
|
||||
force-realloc 1
|
||||
rtcp-omit
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
EXTRA_DIST = osmomgw-usermanual.adoc \
|
||||
osmomgw-usermanual-docinfo.xml \
|
||||
osmomgw-vty-reference.xml \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
@@ -13,11 +12,5 @@ if BUILD_MANUALS
|
||||
VTY_REFERENCE = osmomgw-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
BUILT_REFERENCE_XML = $(builddir)/vty/mgw_vty_reference.xml
|
||||
$(builddir)/vty/mgw_vty_reference.xml: $(top_builddir)/src/osmo-mgw/osmo-mgw
|
||||
mkdir -p $(builddir)/vty
|
||||
$(top_builddir)/src/osmo-mgw/osmo-mgw --vty-ref-xml > $@
|
||||
|
||||
OSMO_REPOSITORY = osmo-mgw
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
|
||||
endif
|
||||
|
||||
@@ -23,13 +23,14 @@ OsmoMGW(config-mgcp)# local ip 127.0.0.1
|
||||
|
||||
=== Configuring the trunk
|
||||
|
||||
The first trunk is considered a virtual trunk in OsmoMGW. All
|
||||
The first trunk (trunk 0) is considered a virtual trunk in OsmoMGW. All
|
||||
endpoints of type "rtpbridge" are routed here. The virtual trunk is configured
|
||||
in the config-mgcp context.
|
||||
|
||||
All other trunks are configured in the config-mgcp-trunk context, but the
|
||||
commands used are identical. Right now trunks are considered only for "ds/e1"
|
||||
type endpoints.
|
||||
commands used are identical. Right now trunks are considered only for ds/e1
|
||||
type endpoints which are not yet implemented. Don't use trunks other than the
|
||||
"virtual" trunk 0.
|
||||
|
||||
.Example: MGCP trunk configuration
|
||||
----
|
||||
@@ -53,72 +54,4 @@ OsmoMGW(config-mgcp)# rtp-patch timestamp <3>
|
||||
<2> Hide SSRC changes
|
||||
<3> Ensure RTP timestamp is aligned with frame duration
|
||||
|
||||
NOTE: Changes to trunks that affect resource allocation, such as newly created
|
||||
trunks or a change of the number of available endpoints, require a full restart
|
||||
of osmo-mgw!
|
||||
|
||||
=== E1 trunk considerations
|
||||
|
||||
While the RTP bridge trunks are natively based on IP no special considerations
|
||||
are required during setup. E1 trunks are mapped on a physical E1 line, which has
|
||||
to be configured as shown below.
|
||||
|
||||
.Example: E1 line setup
|
||||
----
|
||||
OsmoMGW(config-e1_input)# e1_line 0 driver dahdi <1>
|
||||
OsmoMGW(config-e1_input)# e1_line 0 port 2 <2>
|
||||
----
|
||||
<1> Name of the libosmo-abis driver implementation ("dahdi")
|
||||
<2> Port number of the physical E1 port to use (2)
|
||||
|
||||
In osmo-mgw the e1_input node is used to configure the physical E1 line. The
|
||||
line number will be used internally to identify the configured E1 line. The
|
||||
port number is the physical E1 connector (sometimes called 'span') at the E1
|
||||
hardware. Per trunk an individual E1 line will be needed. Beware that the E1
|
||||
driver may also need configuration settings that are not discussed here.
|
||||
|
||||
.Example: E1 trunk setup
|
||||
----
|
||||
OsmoMGW(config-mgcp)# trunk 0 <1>
|
||||
OsmoMGW(config-mgcp-trunk)# line 0 <2>
|
||||
----
|
||||
<1> Creation of a trunk (0)
|
||||
<2> Reference to the E1 line to use (0)
|
||||
|
||||
The E1 trunk is created along with a number, typically starting at 0, but if
|
||||
required any number from 0-64 is allowed. The E1 trunk configuration concerning
|
||||
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
|
||||
that were configured under the e1_input node.
|
||||
|
||||
.Example: A typical configuration with one E1 trunk
|
||||
----
|
||||
e1_input
|
||||
e1_line 0 driver dahdi
|
||||
e1_line 0 port 2
|
||||
mgcp
|
||||
bind ip 127.0.0.1
|
||||
rtp net-range 6000 6011
|
||||
rtp net-bind-ip 192.168.100.130
|
||||
rtp ip-probing
|
||||
rtp ip-dscp 46
|
||||
no rtp keep-alive
|
||||
bind port 2428
|
||||
number endpoints 30
|
||||
loop 0
|
||||
force-realloc 1
|
||||
osmux off
|
||||
rtp-patch rfc5993hr
|
||||
trunk 0
|
||||
rtp keep-alive once
|
||||
no rtp keep-alive
|
||||
line 0
|
||||
----
|
||||
|
||||
NOTE: One E1 trunk always covers a whole E1 line. All subslots (I.640) will be mapped
|
||||
to individual MGCP endpoints. As long as the endpoints remain unused the
|
||||
underlying E1 timeslot is not used.
|
||||
|
||||
NOTE: The E1 trunk implementation also works with T1 lines, however since T1 has
|
||||
24 instead of 31 usable timeslots only the endpoints that fall into that 1-24 timeslot
|
||||
range will be useable.
|
||||
|
||||
@@ -1,79 +1,10 @@
|
||||
|
||||
// autogenerated by show asciidoc counters
|
||||
These counters and their description based on OsmoMGW 1.5.0.64-189f (OsmoMGW).
|
||||
These counters and their description based on OsmoMGW 1.3.0.34-9cd52 (OsmoMGW).
|
||||
|
||||
=== Rate Counters
|
||||
|
||||
// generating tables for rate_ctr_group
|
||||
// rate_ctr_group table aggregated statistics for all rtp connections
|
||||
.all_rtp_conn - aggregated statistics for all rtp connections
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| all_rtp:err_tstmp_in | <<all_rtp_conn_all_rtp:err_tstmp_in>> | Total inbound rtp-stream timestamp errors.
|
||||
| all_rtp:err_tstmp_out | <<all_rtp_conn_all_rtp:err_tstmp_out>> | Total outbound rtp-stream timestamp errors.
|
||||
| all_rtp:packets_rx | <<all_rtp_conn_all_rtp:packets_rx>> | Total inbound rtp packets.
|
||||
| all_rtp:octets_rx | <<all_rtp_conn_all_rtp:octets_rx>> | Total inbound rtp octets.
|
||||
| all_rtp:packets_tx | <<all_rtp_conn_all_rtp:packets_tx>> | Total outbound rtp packets.
|
||||
| all_rtp:octets_tx | <<all_rtp_conn_all_rtp:octets_tx>> | Total outbound rtp octets.
|
||||
| all_rtp:dropped | <<all_rtp_conn_all_rtp:dropped>> | Total dropped rtp packets.
|
||||
| all_rtp:num_closed_conns | <<all_rtp_conn_all_rtp:num_closed_conns>> | Total number of rtp connections closed.
|
||||
|===
|
||||
// rate_ctr_group table dlcx statistics
|
||||
.dlcx - dlcx statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| dlcx:success | <<dlcx_dlcx:success>> | DLCX command processed successfully.
|
||||
| dlcx:wildcard | <<dlcx_dlcx:wildcard>> | wildcard names in DLCX commands are unsupported.
|
||||
| dlcx:no_conn | <<dlcx_dlcx:no_conn>> | endpoint specified in DLCX command has no active connections.
|
||||
| dlcx:callid | <<dlcx_dlcx:callid>> | CallId specified in DLCX command mismatches endpoint's CallId .
|
||||
| dlcx:connid | <<dlcx_dlcx:connid>> | connection ID specified in DLCX command does not exist on endpoint.
|
||||
| dlcx:unhandled_param | <<dlcx_dlcx:unhandled_param>> | unhandled parameter in DLCX command.
|
||||
| dlcx:rejected | <<dlcx_dlcx:rejected>> | connection deletion rejected by policy.
|
||||
| dlcx:deferred | <<dlcx_dlcx:deferred>> | connection deletion deferred by policy.
|
||||
|===
|
||||
// rate_ctr_group table mdcx statistics
|
||||
.mdcx - mdcx statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| mdcx:success | <<mdcx_mdcx:success>> | MDCX command processed successfully.
|
||||
| mdcx:wildcard | <<mdcx_mdcx:wildcard>> | wildcard endpoint names in MDCX commands are unsupported.
|
||||
| mdcx:no_conn | <<mdcx_mdcx:no_conn>> | endpoint specified in MDCX command has no active connections.
|
||||
| mdcx:callid | <<mdcx_mdcx:callid>> | invalid CallId specified in MDCX command.
|
||||
| mdcx:connid | <<mdcx_mdcx:connid>> | invalid connection ID specified in MDCX command.
|
||||
| crcx:unhandled_param | <<mdcx_crcx:unhandled_param>> | unhandled parameter in MDCX command.
|
||||
| mdcx:no_connid | <<mdcx_mdcx:no_connid>> | no connection ID specified in MDCX command.
|
||||
| mdcx:conn_not_found | <<mdcx_mdcx:conn_not_found>> | connection specified in MDCX command does not exist.
|
||||
| mdcx:invalid_mode | <<mdcx_mdcx:invalid_mode>> | invalid connection mode in MDCX command.
|
||||
| mdcx:conn_opt | <<mdcx_mdcx:conn_opt>> | connection options invalid.
|
||||
| mdcx:no_remote_conn_desc | <<mdcx_mdcx:no_remote_conn_desc>> | no opposite end specified for connection.
|
||||
| mdcx:start_rtp_failure | <<mdcx_mdcx:start_rtp_failure>> | failure to start RTP processing.
|
||||
| mdcx:conn_rejected | <<mdcx_mdcx:conn_rejected>> | connection rejected by policy.
|
||||
| mdcx:conn_deferred | <<mdcx_mdcx:conn_deferred>> | connection deferred by policy.
|
||||
|===
|
||||
// rate_ctr_group table crxc statistics
|
||||
.crcx - crxc statistics
|
||||
[options="header"]
|
||||
|===
|
||||
| Name | Reference | Description
|
||||
| crcx:success | <<crcx_crcx:success>> | CRCX command processed successfully.
|
||||
| crcx:bad_action | <<crcx_crcx:bad_action>> | bad action in CRCX command.
|
||||
| crcx:unhandled_param | <<crcx_crcx:unhandled_param>> | unhandled parameter in CRCX command.
|
||||
| crcx:missing_callid | <<crcx_crcx:missing_callid>> | missing CallId in CRCX command.
|
||||
| crcx:invalid_mode | <<crcx_crcx:invalid_mode>> | invalid connection mode in CRCX command.
|
||||
| crcx:limit_exceeded | <<crcx_crcx:limit_exceeded>> | limit of concurrent connections was reached.
|
||||
| crcx:unkown_callid | <<crcx_crcx:unkown_callid>> | unknown CallId in CRCX command.
|
||||
| crcx:alloc_conn_fail | <<crcx_crcx:alloc_conn_fail>> | connection allocation failure.
|
||||
| crcx:no_remote_conn_desc | <<crcx_crcx:no_remote_conn_desc>> | no opposite end specified for connection.
|
||||
| crcx:start_rtp_failure | <<crcx_crcx:start_rtp_failure>> | failure to start RTP processing.
|
||||
| crcx:conn_rejected | <<crcx_crcx:conn_rejected>> | connection rejected by policy.
|
||||
| crcx:no_osmux | <<crcx_crcx:no_osmux>> | no osmux offered by peer.
|
||||
| crcx:conn_opt | <<crcx_crcx:conn_opt>> | connection options invalid.
|
||||
| crcx:codec_nego | <<crcx_crcx:codec_nego>> | codec negotiation failure.
|
||||
| crcx:bind_port | <<crcx_crcx:bind_port>> | port bind failure.
|
||||
|===
|
||||
== Osmo Stat Items
|
||||
|
||||
// generating tables for osmo_stat_items
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
== MGCP Endpoints
|
||||
|
||||
MGCP organizes the switching resources in so called endpoints. Each endpoint is
|
||||
referenced by its unique identifier. While RFC 3435 specifies a naming scheme, the
|
||||
actual identifier naming is subject to the implementation and configuration.
|
||||
|
||||
=== RTP proxy / RTP bridge endpoints
|
||||
|
||||
OsmoMGW implements a freely configurable number of `rtpbridge` endpoints. Those
|
||||
endpoints are able to host two connections at a time to model the functionality
|
||||
of a tandem switch.
|
||||
|
||||
RTP bridge endpoint identifiers are referenced by the string `rtpbridge/`, a
|
||||
hexadecimal number without leading zeros and a domain name (configurable).
|
||||
|
||||
----
|
||||
rtpbridge/<number>@<domain>
|
||||
----
|
||||
|
||||
.Example: List of virtual endpoints
|
||||
----
|
||||
rtpbridge/1@mgw
|
||||
rtpbridge/2@mgw
|
||||
rtpbridge/3@mgw
|
||||
rtpbridge/4@mgw
|
||||
rtpbridge/5@mgw
|
||||
rtpbridge/6@mgw
|
||||
rtpbridge/7@mgw
|
||||
rtpbridge/8@mgw
|
||||
rtpbridge/9@mgw
|
||||
rtpbridge/a@mgw
|
||||
rtpbridge/b@mgw
|
||||
rtpbridge/c@mgw
|
||||
rtpbridge/d@mgw
|
||||
rtpbridge/e@mgw
|
||||
rtpbridge/f@mgw
|
||||
rtpbridge/10@mgw
|
||||
----
|
||||
|
||||
=== E1/T1 endpoints
|
||||
|
||||
OsmoMGW supports E1 subslot multiplexing as specified by I.460. All possible
|
||||
subslot combinations are mapped on individual endpoints. The endpoint names
|
||||
are prefixed with `ds/e1-` followed by the trunk number and the E1 timeslot.
|
||||
The subslot is defined by a bit rate and a bit offset.
|
||||
|
||||
----
|
||||
ds/e1-<trunk>/s-<timeslot>/su<bitrate>-<bitoffset>@<domain>
|
||||
----
|
||||
|
||||
.Example: List of endpoints on E1 trunk 0 at E1 timeslot 2
|
||||
----
|
||||
ds/e1-0/s-2/su64-0@mgw
|
||||
ds/e1-0/s-2/su32-0@mgw
|
||||
ds/e1-0/s-2/su32-4@mgw
|
||||
ds/e1-0/s-2/su16-0@mgw
|
||||
ds/e1-0/s-2/su16-2@mgw
|
||||
ds/e1-0/s-2/su16-4@mgw
|
||||
ds/e1-0/s-2/su16-6@mgw
|
||||
ds/e1-0/s-2/su8-0@mgw
|
||||
ds/e1-0/s-2/su8-1@mgw
|
||||
ds/e1-0/s-2/su8-2@mgw
|
||||
ds/e1-0/s-2/su8-3@mgw
|
||||
ds/e1-0/s-2/su8-4@mgw
|
||||
ds/e1-0/s-2/su8-5@mgw
|
||||
ds/e1-0/s-2/su8-6@mgw
|
||||
ds/e1-0/s-2/su8-7@mgw
|
||||
----
|
||||
|
||||
When creating connections on endpoints that reside in one E1 timeslot the call
|
||||
agent must make sure that no overlapping endpoints are used. It is for example
|
||||
not possible to use `ds/e1-0/s-2/su16-2@mgw` and `ds/e1-0/s-2/su8-3@mgw` at the
|
||||
same time because they overlap.
|
||||
|
||||
.Subslot overlapping
|
||||
[options="header"]
|
||||
|===
|
||||
| Bit offset 4+| Subslots
|
||||
| 0 | 8k .2+| 16k .4+| 32k .8+| 64k
|
||||
| 1 | 8k
|
||||
| 2 | 8k .2+| 16k
|
||||
| 3 | 8k
|
||||
| 4 | 8k .2+| 16k .4+| 32k
|
||||
| 5 | 8k
|
||||
| 6 | 8k .2+| 16k
|
||||
| 7 | 8k
|
||||
|===
|
||||
|
||||
NOTE: The current implementation (December 2020) only implements TRAU frame
|
||||
encoding/decoding for 16K and 8K subslots. Endpoints with other bitrates are
|
||||
not yet useable.
|
||||
|
||||
NOTE: the VTY command "show mgcp" can be used to get a list of all available
|
||||
endpoints (including identifiers)
|
||||
@@ -11,7 +11,7 @@ indicate collisions or configuration errors.
|
||||
|
||||
==== `X-Osmo-IGN` Format
|
||||
|
||||
The value part of `X-Osmo-IGN` must be one or more items separated by one or more
|
||||
The value part of X-Osmo-IGN must be one or more items separated by one or more
|
||||
spaces. Each item consists of one or more non-whitespace characters.
|
||||
|
||||
.Example: `X-Osmo-IGN` format with three ficticious items "X", "abc" and "123".
|
||||
@@ -19,7 +19,7 @@ spaces. Each item consists of one or more non-whitespace characters.
|
||||
X-Osmo-IGN: X abc 123
|
||||
----
|
||||
|
||||
`X-Osmo-IGN` must be issued in the MGCP header section (typically as its last item),
|
||||
`X-Osmo-IGN` must be issued in the MGCP section (typically as its last item),
|
||||
before the SDP section starts.
|
||||
|
||||
==== Supported `X-Osmo-IGN` Items
|
||||
@@ -66,7 +66,3 @@ m=audio 5904 RTP/AVP 97
|
||||
a=rtpmap:97 GSM-EFR/8000
|
||||
a=ptime:40
|
||||
----
|
||||
|
||||
=== `X-Osmux`
|
||||
|
||||
See <<mgcp-extension-osmux>>
|
||||
|
||||
@@ -21,10 +21,10 @@ Protocol.
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
OsmoBTS -> OsmoBSC [label="Abis/IP"];
|
||||
OsmoBSC -> "core-network" [label="3GPP AoIP"];
|
||||
OsmoBSC -> OsmoMSC [label="3GPP AoIP"];
|
||||
OsmoBSC -> OsmoMGW [label="MGCP"];
|
||||
OsmoBTS -> OsmoMGW [label="RTP",dir=both];
|
||||
OsmoMGW -> "core-network" [label="RTP",dir=both];
|
||||
OsmoMGW -> OsmoMSC [label="RTP",dir=both];
|
||||
{rank=same OsmoBSC OsmoMGW}
|
||||
OsmoMGW [color=red];
|
||||
}
|
||||
@@ -36,9 +36,10 @@ digraph G {
|
||||
----
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
"2G BSS" -> OsmoMSC [label="3GPP AoIP"];
|
||||
BTS -> BSC [label="Abis"];
|
||||
BSC -> OsmoMSC [label="3GPP AoIP"];
|
||||
OsmoMSC -> OsmoMGW [label="MGCP"];
|
||||
"2G BSS" -> OsmoMGW [label="RTP",dir=both];
|
||||
BSC -> OsmoMGW [label="RTP",dir=both];
|
||||
OsmoMSC -> OsmoSIP [label="MNCC"];
|
||||
OsmoSIP -> PBX [label="SIP Trunk"];
|
||||
OsmoMGW -> PBX [label="RTP",dir=both];
|
||||
@@ -52,22 +53,6 @@ digraph G {
|
||||
}
|
||||
----
|
||||
|
||||
[[fig-bsc-e1]]
|
||||
.Integration of legacy E1 BTS in AoIP network
|
||||
[graphviz]
|
||||
----
|
||||
digraph G {
|
||||
rankdir = LR;
|
||||
BTS -> OsmoBSC [label="Abis/E1"];
|
||||
OsmoBSC -> "core-network" [label="3GPP AoIP"];
|
||||
OsmoBSC -> OsmoMGW [label="MGCP"];
|
||||
BTS -> OsmoMGW [label="TRAU/E1",dir=both];
|
||||
OsmoMGW -> "core-network" [label="RTP",dir=both];
|
||||
{rank=same OsmoBSC OsmoMGW}
|
||||
OsmoMGW [color=red];
|
||||
}
|
||||
----
|
||||
|
||||
=== Software Components
|
||||
|
||||
OsmoMGW contains a variety of different software components, which we’ll
|
||||
@@ -92,14 +77,14 @@ Transcoding is currently not supported in OsmoMGW.
|
||||
|
||||
=== Limitations
|
||||
|
||||
At the moment (November 2020), OsmoMGW implements RTP proxy / RTP bridge
|
||||
type endpoints and E1/T1 16k/8k sub-slots with TRAU frames for classic BTS
|
||||
support. To the RTP proxy / RTP bridge endpoints two RTP connections can
|
||||
be established, which then work as a tandem. E1/T1 endpoints support one
|
||||
RTP connection at a time that is associated with a sub-slot on an E1 line.
|
||||
We are planning to add further endpoint types for:
|
||||
Osmux is not yet supported in OsmoMGW.
|
||||
|
||||
At the moment (July 2018), OsmoMGW only implements RTP proxy / RTP bridge
|
||||
type endpoints, to each of which two RTP connections can be established.
|
||||
We are planning to add endpoint types for:
|
||||
|
||||
- classic E1/T1 timeslots (64kBps alaw/ulaw)
|
||||
- classic E1/T1 16k sub-slots with TRAU frames for classic BTS support
|
||||
- announcement/playout end-points
|
||||
- conference endpoints
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
==== Full example of QoS for osmo-mgw
|
||||
|
||||
In the below example we will show the full set of configuration required
|
||||
for both DSCP and PCP differentiation of RTP traffic by osmo-mgw.
|
||||
|
||||
What we want to achieve in this example is the following configuration:
|
||||
|
||||
.DSCP and PCP assignments for osmo-mgw Abis downlink traffic in this example
|
||||
[options="header",width="30%",cols="2,1,1"]
|
||||
|===
|
||||
|Traffic |DSCP|PCP
|
||||
|RTP | 46| 6
|
||||
|===
|
||||
|
||||
. configure the osmo-mgw program to set the DSCP value
|
||||
. configure an egrees QoS map to map from priority to PCP
|
||||
|
||||
.Example Step 1: add related VTY configuration to `osmo-mgw.cfg`
|
||||
----
|
||||
...
|
||||
mgcp
|
||||
rtp ip-dscp 46
|
||||
rtp socket-priority 6
|
||||
...
|
||||
----
|
||||
|
||||
.Example Step 2: egress QoS map to map from socket priority to PCP values
|
||||
----
|
||||
$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 5:5 6:6 7:7 <2>
|
||||
----
|
||||
<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
|
||||
<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also include the
|
||||
mapping 5:5 and 7:7 from the osmo-bsc example (see <<userman-osmobsc>>) here.
|
||||
|
||||
NOTE:: The settings of the `ip` command are volatile and only active until
|
||||
the next reboot (or the network device or VLAN is removed). Please refer to
|
||||
the documentation of your specific Linux distribution in order to find out how
|
||||
to make such settings persistent by means of an `ifup` hook whenever the interface
|
||||
comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
|
||||
script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu,
|
||||
this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
|
||||
script.
|
||||
@@ -12,7 +12,7 @@ arguments:
|
||||
*-h, --help*::
|
||||
Print a short help message about the supported options
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the program
|
||||
Print the compile-time version number of the OsmoBTS program
|
||||
*-D, --daemonize*::
|
||||
Fork the process as a daemon into background.
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
|
||||
@@ -18,18 +18,10 @@ include::./common/chapters/logging.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/configuration.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/mgcp_endpoints.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/mgcp_extensions.adoc[]
|
||||
|
||||
include::./common/chapters/osmux/osmux.adoc[]
|
||||
|
||||
include::./common/chapters/qos-dscp-pcp.adoc[]
|
||||
|
||||
//include::{srcdir}/chapters/counters.adoc[]
|
||||
|
||||
include::./common/chapters/vty_cpu_sched.adoc[]
|
||||
|
||||
include::./common/chapters/port_numbers.adoc[]
|
||||
|
||||
include::./common/chapters/bibliography.adoc[]
|
||||
@@ -37,3 +29,5 @@ include::./common/chapters/bibliography.adoc[]
|
||||
include::./common/chapters/glossary.adoc[]
|
||||
|
||||
include::./common/chapters/gfdl.adoc[]
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
|
||||
OSMO_MGW_BRANCH=$COMMIT ./regen_doc.sh osmo-mgw 4243 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/mgw_vty_reference.xml"
|
||||
1645
doc/manuals/vty/mgw_vty_reference.xml
Normal file
1645
doc/manuals/vty/mgw_vty_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,16 +4,10 @@ SUBDIRS = \
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
osmocom/mgcp_client/mgcp_client.h \
|
||||
osmocom/mgcp_client/mgcp_client_endpoint_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_client_fsm.h \
|
||||
osmocom/mgcp_client/mgcp_client_pool.h \
|
||||
osmocom/mgcp_client/mgcp_common.h \
|
||||
osmocom/mgcp/mgcp.h \
|
||||
osmocom/mgcp/mgcp_common.h \
|
||||
osmocom/mgcp/mgcp_internal.h \
|
||||
osmocom/mgcp/osmux.h \
|
||||
$(NULL)
|
||||
|
||||
# This gets copied during make from osmocom/mgcp/mgcp_common.h. Therefore it is not included in the source tree and we
|
||||
# don't need to distribute it (OS#4084).
|
||||
nobase_nodist_include_HEADERS = \
|
||||
osmocom/mgcp_client/mgcp_common.h \
|
||||
$(NULL)
|
||||
|
||||
@@ -6,11 +6,5 @@ noinst_HEADERS = \
|
||||
mgcp_endp.h \
|
||||
mgcp_sdp.h \
|
||||
mgcp_codec.h \
|
||||
mgcp_ctrl.h \
|
||||
mgcp_trunk.h \
|
||||
debug.h \
|
||||
mgcp_ratectr.h \
|
||||
mgcp_e1.h \
|
||||
mgcp_network.h \
|
||||
mgcp_protocol.h \
|
||||
$(NULL)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/* Debug Areas of the code */
|
||||
enum {
|
||||
DRTP,
|
||||
DE1,
|
||||
DIUUP,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
||||
41
include/osmocom/mgcp/iuup_cn_node.h
Normal file
41
include/osmocom/mgcp/iuup_cn_node.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* IuUP CN node, minimal implementation */
|
||||
|
||||
/* _____IuUP_CN_____
|
||||
* | |
|
||||
* UE <--> RNC --PDU-> osmo_iuup_cn_rx_pdu() -+-> ---+-> rx_payload()
|
||||
* | | |
|
||||
* | <-PDU-- tx_msg() <-------------+-- <-+--- osmo_iuup_cn_tx_payload()
|
||||
* | |
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct osmo_iuup_cn;
|
||||
struct msgb;
|
||||
|
||||
typedef int (*osmo_iuup_data_cb_t)(struct msgb *msg, void *node_priv);
|
||||
|
||||
struct osmo_iuup_cn_cfg {
|
||||
void *node_priv;
|
||||
|
||||
/* When the IuUP peer sent a voice packet, the clean RTP without the IuUP header is fed to this
|
||||
* callback. */
|
||||
osmo_iuup_data_cb_t rx_payload;
|
||||
|
||||
/* IuUP handler requests that a PDU shall be sent to the IuUP peer (e.g. the RNC).
|
||||
* It is guaranteed that the msgb->dst pointer is preserved or copied from the msgb that
|
||||
* originated the request. */
|
||||
osmo_iuup_data_cb_t tx_msg;
|
||||
};
|
||||
|
||||
bool osmo_iuup_cn_is_iuup_init(struct msgb *msg);
|
||||
|
||||
struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
|
||||
const char *name_fmt, ...);
|
||||
void osmo_iuup_cn_free(struct osmo_iuup_cn *cn);
|
||||
|
||||
int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *payload);
|
||||
|
||||
int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu);
|
||||
117
include/osmocom/mgcp/iuup_protocol.h
Normal file
117
include/osmocom/mgcp/iuup_protocol.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* IuUP protocol handling, minimal implementation */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/endian.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#define OSMO_IUUP_HEADROOM 32
|
||||
|
||||
enum osmo_iuup_pdu_type {
|
||||
OSMO_IUUP_PDU_DATA_WITH_CRC = 0,
|
||||
OSMO_IUUP_PDU_CONTROL_PROCEDURE = 14,
|
||||
};
|
||||
|
||||
enum osmo_iuup_acknack {
|
||||
OSMO_IUUP_ACKNACK_PROCEDURE = 0,
|
||||
OSMO_IUUP_ACKNACK_ACK = 1,
|
||||
OSMO_IUUP_ACKNACK_NACK = 2,
|
||||
};
|
||||
|
||||
enum osmo_iuup_procedure {
|
||||
OSMO_IUUP_PROC_INITIALIZATION = 0,
|
||||
OSMO_IUUP_PROC_RATE_CONTROL = 1,
|
||||
OSMO_IUUP_PROC_TIME_ALIGNMENT = 2,
|
||||
OSMO_IUUP_PROC_ERROR_EVENT = 3,
|
||||
};
|
||||
|
||||
enum osmo_iuup_frame_good {
|
||||
OSMO_IUUP_FRAME_GOOD = 0,
|
||||
OSMO_IUUP_FRAME_BAD = 1,
|
||||
OSMO_IUUP_FRAME_BAD_DUE_TO_RADIO = 2,
|
||||
};
|
||||
|
||||
struct osmo_iuup_hdr_ctrl {
|
||||
#if OSMO_IS_BIG_ENDIAN
|
||||
uint8_t pdu_type:4,
|
||||
ack_nack:2,
|
||||
frame_nr:2;
|
||||
uint8_t mode_version:4,
|
||||
procedure:4;
|
||||
uint8_t header_crc:6,
|
||||
payload_crc_hi:2;
|
||||
uint8_t payload_crc_lo;
|
||||
uint8_t payload[0];
|
||||
#elif OSMO_IS_LITTLE_ENDIAN
|
||||
uint8_t frame_nr:2,
|
||||
ack_nack:2,
|
||||
pdu_type:4;
|
||||
uint8_t procedure:4,
|
||||
mode_version:4;
|
||||
uint8_t payload_crc_hi:2,
|
||||
header_crc:6;
|
||||
uint8_t payload_crc_lo;
|
||||
uint8_t payload[0];
|
||||
#endif
|
||||
} __attribute__((packed));
|
||||
|
||||
union osmo_iuup_hdr_ctrl_payload {
|
||||
struct {
|
||||
#if OSMO_IS_BIG_ENDIAN
|
||||
uint8_t spare:3,
|
||||
iptis_present:1,
|
||||
subflows:3,
|
||||
chain:1;
|
||||
#elif OSMO_IS_LITTLE_ENDIAN
|
||||
uint8_t spare:3,
|
||||
iptis_present:1,
|
||||
subflows:3,
|
||||
chain:1;
|
||||
#endif
|
||||
} initialization;
|
||||
|
||||
struct {
|
||||
#if OSMO_IS_BIG_ENDIAN
|
||||
uint8_t error_distance:2,
|
||||
error_cause:6;
|
||||
#elif OSMO_IS_LITTLE_ENDIAN
|
||||
uint8_t error_cause:6,
|
||||
error_distance:2;
|
||||
#endif
|
||||
} error_event;
|
||||
};
|
||||
|
||||
extern const struct value_string osmo_iuup_error_cause_names[];
|
||||
static inline const char *osmo_iuup_error_cause_name(uint8_t val)
|
||||
{ return get_value_string(osmo_iuup_error_cause_names, val); }
|
||||
|
||||
struct osmo_iuup_hdr_data {
|
||||
#if OSMO_IS_BIG_ENDIAN
|
||||
uint8_t pdu_type:4,
|
||||
frame_nr:4;
|
||||
uint8_t frame_good:2,
|
||||
rfci:6;
|
||||
uint8_t header_crc:6,
|
||||
payload_crc_hi:2;
|
||||
uint8_t payload_crc_lo;
|
||||
#elif OSMO_IS_LITTLE_ENDIAN
|
||||
uint8_t frame_nr:4,
|
||||
pdu_type:4;
|
||||
uint8_t rfci:6,
|
||||
frame_good:2;
|
||||
uint8_t payload_crc_hi:2,
|
||||
header_crc:6;
|
||||
uint8_t payload_crc_lo;
|
||||
#endif
|
||||
uint8_t payload[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
int osmo_iuup_classify(bool log_errors,
|
||||
const char *log_label,
|
||||
struct msgb *pdu,
|
||||
struct osmo_iuup_hdr_ctrl **is_ctrl,
|
||||
struct osmo_iuup_hdr_data **is_data);
|
||||
bool osmo_iuup_is_init(struct msgb *pdu);
|
||||
void osmo_iuup_make_init_ack(struct msgb *ack);
|
||||
void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len);
|
||||
@@ -23,7 +23,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
@@ -34,9 +33,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "mgcp_ratectr.h"
|
||||
|
||||
#define RTP_PORT_DEFAULT_RANGE_START 16002
|
||||
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
|
||||
@@ -46,7 +42,7 @@
|
||||
*/
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_config;
|
||||
struct mgcp_trunk;
|
||||
struct mgcp_trunk_config;
|
||||
struct mgcp_rtp_end;
|
||||
|
||||
#define MGCP_ENDP_CRCX 1
|
||||
@@ -63,7 +59,10 @@ struct mgcp_rtp_end;
|
||||
#define MGCP_POLICY_REJECT 5
|
||||
#define MGCP_POLICY_DEFER 6
|
||||
|
||||
typedef int (*mgcp_reset)(struct mgcp_trunk *cfg);
|
||||
typedef int (*mgcp_realloc)(struct mgcp_trunk_config *cfg, int endpoint);
|
||||
typedef int (*mgcp_change)(struct mgcp_trunk_config *cfg, int endpoint, int state);
|
||||
typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int state, const char *transactio_id);
|
||||
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
|
||||
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
|
||||
|
||||
/**
|
||||
@@ -82,21 +81,18 @@ typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
struct mgcp_rtp_codec;
|
||||
|
||||
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_codec **codec,
|
||||
const char **fmtp_extra,
|
||||
int *payload_type,
|
||||
const char**subtype_name,
|
||||
const char**fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/**
|
||||
* This holds information on how to allocate ports
|
||||
*/
|
||||
struct mgcp_port_range {
|
||||
pthread_mutex_t lock;
|
||||
/* addr or NULL to fall-back to default */
|
||||
char bind_addr_v4[INET6_ADDRSTRLEN];
|
||||
char bind_addr_v6[INET6_ADDRSTRLEN];
|
||||
char *bind_addr;
|
||||
|
||||
/* dynamically allocated */
|
||||
int range_start;
|
||||
@@ -122,6 +118,103 @@ struct mgcp_port_range {
|
||||
#define MGCP_KEEPALIVE_ONCE (-1)
|
||||
#define MGCP_KEEPALIVE_NEVER 0
|
||||
|
||||
/* Global MCGP CRCX related rate counters */
|
||||
enum {
|
||||
MGCP_CRCX_SUCCESS,
|
||||
MGCP_CRCX_FAIL_BAD_ACTION,
|
||||
MGCP_CRCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_CRCX_FAIL_MISSING_CALLID,
|
||||
MGCP_CRCX_FAIL_INVALID_MODE,
|
||||
MGCP_CRCX_FAIL_LIMIT_EXCEEDED,
|
||||
MGCP_CRCX_FAIL_UNKNOWN_CALLID,
|
||||
MGCP_CRCX_FAIL_ALLOC_CONN,
|
||||
MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_CRCX_FAIL_START_RTP,
|
||||
MGCP_CRCX_FAIL_REJECTED_BY_POLICY,
|
||||
MGCP_CRCX_FAIL_NO_OSMUX,
|
||||
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
|
||||
MGCP_CRCX_FAIL_BIND_PORT,
|
||||
};
|
||||
|
||||
/* Global MCGP MDCX related rate counters */
|
||||
enum {
|
||||
MGCP_MDCX_SUCCESS,
|
||||
MGCP_MDCX_FAIL_WILDCARD,
|
||||
MGCP_MDCX_FAIL_NO_CONN,
|
||||
MGCP_MDCX_FAIL_INVALID_CALLID,
|
||||
MGCP_MDCX_FAIL_INVALID_CONNID,
|
||||
MGCP_MDCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_MDCX_FAIL_NO_CONNID,
|
||||
MGCP_MDCX_FAIL_CONN_NOT_FOUND,
|
||||
MGCP_MDCX_FAIL_INVALID_MODE,
|
||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_MDCX_FAIL_START_RTP,
|
||||
MGCP_MDCX_FAIL_REJECTED_BY_POLICY,
|
||||
MGCP_MDCX_DEFERRED_BY_POLICY
|
||||
};
|
||||
|
||||
/* Global MCGP DLCX related rate counters */
|
||||
enum {
|
||||
MGCP_DLCX_SUCCESS,
|
||||
MGCP_DLCX_FAIL_WILDCARD,
|
||||
MGCP_DLCX_FAIL_NO_CONN,
|
||||
MGCP_DLCX_FAIL_INVALID_CALLID,
|
||||
MGCP_DLCX_FAIL_INVALID_CONNID,
|
||||
MGCP_DLCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_DLCX_FAIL_REJECTED_BY_POLICY,
|
||||
MGCP_DLCX_DEFERRED_BY_POLICY,
|
||||
};
|
||||
|
||||
struct mgcp_trunk_config {
|
||||
struct llist_head entry;
|
||||
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
int trunk_nr;
|
||||
int trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
char *audio_name;
|
||||
int audio_payload;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
int audio_loop;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* timer */
|
||||
struct osmo_timer_list keepalive_timer;
|
||||
|
||||
/* When set, incoming RTP packets are not filtered
|
||||
* when ports and ip-address do not match (debug) */
|
||||
int rtp_accept_all;
|
||||
|
||||
unsigned int number_endpoints;
|
||||
int vty_number_endpoints;
|
||||
struct mgcp_endpoint *endpoints;
|
||||
|
||||
/* Rate counter group which contains stats for processed CRCX commands. */
|
||||
struct rate_ctr_group *mgcp_crcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed MDCX commands. */
|
||||
struct rate_ctr_group *mgcp_mdcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed DLCX commands. */
|
||||
struct rate_ctr_group *mgcp_dlcx_ctr_group;
|
||||
/* Rate counter group which aggregates stats of individual RTP connections. */
|
||||
struct rate_ctr_group *all_rtp_conn_stats;
|
||||
};
|
||||
|
||||
enum mgcp_role {
|
||||
MGCP_BSC = 0,
|
||||
MGCP_BSC_NAT,
|
||||
@@ -129,9 +222,9 @@ enum mgcp_role {
|
||||
|
||||
struct mgcp_config {
|
||||
int source_port;
|
||||
char local_ip[INET6_ADDRSTRLEN];
|
||||
char source_addr[INET6_ADDRSTRLEN];
|
||||
char call_agent_addr[INET6_ADDRSTRLEN];
|
||||
char *local_ip;
|
||||
char *source_addr;
|
||||
char *call_agent_addr;
|
||||
|
||||
/* RTP processing */
|
||||
mgcp_processing rtp_processing_cb;
|
||||
@@ -143,15 +236,20 @@ struct mgcp_config {
|
||||
|
||||
struct mgcp_port_range net_ports;
|
||||
int endp_dscp;
|
||||
int endp_priority;
|
||||
|
||||
int force_ptime;
|
||||
|
||||
mgcp_change change_cb;
|
||||
mgcp_policy policy_cb;
|
||||
mgcp_reset reset_cb;
|
||||
mgcp_realloc realloc_cb;
|
||||
mgcp_rqnt rqnt_cb;
|
||||
void *data;
|
||||
|
||||
/* list holding the trunks */
|
||||
uint32_t last_call_id;
|
||||
|
||||
/* trunk handling */
|
||||
struct mgcp_trunk_config trunk;
|
||||
struct llist_head trunks;
|
||||
|
||||
enum mgcp_role role;
|
||||
@@ -159,7 +257,7 @@ struct mgcp_config {
|
||||
/* osmux translator: 0 means disabled, 1 means enabled */
|
||||
int osmux;
|
||||
/* addr to bind the server to */
|
||||
char osmux_addr[INET6_ADDRSTRLEN];
|
||||
char *osmux_addr;
|
||||
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
|
||||
* the osmux socket is already initialized.
|
||||
*/
|
||||
@@ -176,16 +274,6 @@ struct mgcp_config {
|
||||
uint16_t osmux_dummy;
|
||||
/* domain name of the media gateway */
|
||||
char domain[255+1];
|
||||
|
||||
/* time after which inactive connections (CIs) get closed */
|
||||
int conn_timeout;
|
||||
|
||||
/* osmocom CTRL interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
|
||||
/* global rate counters to measure the MGWs overall performance and
|
||||
* health */
|
||||
struct mgcp_ratectr_global ratectr;
|
||||
};
|
||||
|
||||
/* config management */
|
||||
@@ -193,7 +281,8 @@ struct mgcp_config *mgcp_config_alloc(void);
|
||||
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
|
||||
enum mgcp_role role);
|
||||
int mgcp_vty_init(void);
|
||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval);
|
||||
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
|
||||
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
|
||||
|
||||
/*
|
||||
* format helper functions
|
||||
@@ -201,10 +290,9 @@ void mgcp_trunk_set_keepalive(struct mgcp_trunk *trunk, int interval);
|
||||
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
|
||||
|
||||
|
||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp);
|
||||
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
|
||||
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,
|
||||
uint8_t prio);
|
||||
int mgcp_udp_send(int fd, struct osmo_sockaddr *addr, int port, const char *buf, int len);
|
||||
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
|
||||
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
|
||||
|
||||
#define PTYPE_UNDEFINED (-1)
|
||||
|
||||
struct mgcp_conn_rtp;
|
||||
|
||||
void mgcp_codec_summary(struct mgcp_conn_rtp *conn);
|
||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn);
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param);
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name);
|
||||
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);
|
||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
|
||||
const char *subtype_name, unsigned int match_nr);
|
||||
|
||||
@@ -50,7 +50,6 @@ enum mgcp_connection_mode {
|
||||
};
|
||||
|
||||
#define MGCP_X_OSMO_IGN_HEADER "X-Osmo-IGN:"
|
||||
#define MGCP_X_OSMO_OSMUX_HEADER "X-Osmux:"
|
||||
|
||||
/* Values should be bitwise-OR-able */
|
||||
enum mgcp_x_osmo_ign {
|
||||
@@ -58,12 +57,6 @@ enum mgcp_x_osmo_ign {
|
||||
MGCP_X_OSMO_IGN_CALLID = 1,
|
||||
};
|
||||
|
||||
/* Codec parameters (communicated via SDP/fmtp) */
|
||||
struct mgcp_codec_param {
|
||||
bool amr_octet_aligned_present;
|
||||
bool amr_octet_aligned;
|
||||
};
|
||||
|
||||
/* Ensure that the msg->l2h is NUL terminated. */
|
||||
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
{
|
||||
@@ -100,10 +93,6 @@ static inline int mgcp_msg_terminate_nul(struct msgb *msg)
|
||||
/* A prefix to denote the virtual trunk (RTP on both ends) */
|
||||
#define MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK "rtpbridge/"
|
||||
|
||||
/* A prefix to denote the e1 trunk
|
||||
* (see also RFC3435 section E.2) */
|
||||
#define MGCP_ENDPOINT_PREFIX_E1_TRUNK "ds/e1-"
|
||||
|
||||
/* Maximal number of payload types / codecs that can be negotiated via SDP at
|
||||
* at once. */
|
||||
#define MGCP_MAX_CODECS 10
|
||||
|
||||
@@ -23,114 +23,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_network.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LOGPCONN(conn, cat, level, fmt, args...) \
|
||||
LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
|
||||
(conn)->id, \
|
||||
## args)
|
||||
|
||||
#define LOG_CONN(conn, level, fmt, args...) \
|
||||
LOGP(DRTP, level, "(%s I:%s) " fmt, \
|
||||
(conn)->endp ? (conn)->endp->name : "none", (conn)->id, ## args)
|
||||
|
||||
#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
|
||||
LOG_CONN((conn_rtp)->conn, level, fmt, ## args)
|
||||
|
||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
|
||||
enum mgcp_conn_rtp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
};
|
||||
|
||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||
* contains a useful connection description (currently only RTP) */
|
||||
enum mgcp_conn_type {
|
||||
MGCP_CONN_TYPE_RTP,
|
||||
};
|
||||
|
||||
/* MGCP connection (RTP) */
|
||||
struct mgcp_conn_rtp {
|
||||
|
||||
/* Backpointer to conn struct */
|
||||
struct mgcp_conn *conn;
|
||||
|
||||
/* Specific connection type */
|
||||
enum mgcp_conn_rtp_type type;
|
||||
|
||||
/* Port status */
|
||||
struct mgcp_rtp_end end;
|
||||
|
||||
/* Sequence bits */
|
||||
struct mgcp_rtp_state state;
|
||||
|
||||
/* taps for the rtp connection; one per direction */
|
||||
struct mgcp_rtp_tap tap_in;
|
||||
struct mgcp_rtp_tap tap_out;
|
||||
|
||||
/* Osmux states (optional) */
|
||||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Is cid holding valid data? is it allocated from pool? */
|
||||
bool cid_allocated;
|
||||
/* Allocated Osmux circuit ID for this conn */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
} osmux;
|
||||
|
||||
struct rate_ctr_group *rate_ctr_group;
|
||||
};
|
||||
|
||||
/*! MGCP connection (untyped) */
|
||||
struct mgcp_conn {
|
||||
/*! list head */
|
||||
struct llist_head entry;
|
||||
|
||||
/*! Backpointer to the endpoint where the conn belongs to */
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/*! type of the connection (union) */
|
||||
enum mgcp_conn_type type;
|
||||
|
||||
/*! mode of the connection */
|
||||
enum mgcp_connection_mode mode;
|
||||
|
||||
/*! copy of the mode to restore the original setting (VTY) */
|
||||
enum mgcp_connection_mode mode_orig;
|
||||
|
||||
/*! connection id to identify the connection */
|
||||
char id[MGCP_CONN_ID_MAXLEN];
|
||||
|
||||
/*! human readable name (vty, logging) */
|
||||
char name[256];
|
||||
|
||||
/*! activity tracker (for cleaning up inactive connections) */
|
||||
struct osmo_timer_list watchdog;
|
||||
|
||||
/*! union with connection description */
|
||||
union {
|
||||
struct mgcp_conn_rtp rtp;
|
||||
} u;
|
||||
|
||||
/*! pointer to optional private data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* RTP connection related counters */
|
||||
enum {
|
||||
IN_STREAM_ERR_TSTMP_CTR,
|
||||
@@ -171,11 +68,6 @@ 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."}
|
||||
};
|
||||
|
||||
/* Was conn configured to handle Osmux? */
|
||||
static inline bool mgcp_conn_rtp_is_osmux(const struct mgcp_conn_rtp *conn) {
|
||||
return conn->type == MGCP_OSMUX_BSC || conn->type == MGCP_OSMUX_BSC_NAT;
|
||||
}
|
||||
|
||||
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
||||
enum mgcp_conn_type type, char *name);
|
||||
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id);
|
||||
@@ -186,5 +78,3 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp);
|
||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp);
|
||||
char *mgcp_conn_dump(struct mgcp_conn *conn);
|
||||
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn);
|
||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp);
|
||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
|
||||
const char *bind_addr, uint16_t port);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* A 64k timeslot on an E1 line can be subdevied into the following
|
||||
* subslot combinations:
|
||||
*
|
||||
* subslot: offset:
|
||||
* [ ][ ][ 16k ][8k_subslot] 0
|
||||
* [ ][ 32k ][_subslot__][8k_subslot] 1
|
||||
* [ ][ subslot ][ 16k ][8k_subslot] 2
|
||||
* [ 64k ][__________][_subslot__][8k_subslot] 3
|
||||
* [ timeslot ][ ][ 16k ][8k_subslot] 4
|
||||
* [ ][ 32K ][_subslot__][8k_subslot] 5
|
||||
* [ ][ subslot ][ 16k ][8k_subslot] 6
|
||||
* [ ][ ][ subslot ][8k_subslot] 7
|
||||
*
|
||||
* Since overlapping assignment of subslots is not possible there is a limited
|
||||
* set of subslot assignments possible. The e1_rates array lists the possible
|
||||
* assignments as depicted above. Also each subslot assignment comes along with
|
||||
* a bit offset in the E1 bitstream. The e1_offsets arrays lists the bit
|
||||
* offsets. */
|
||||
static const uint8_t e1_rates[] = { 64, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8, 8, 8 };
|
||||
static const uint8_t e1_offsets[] = { 0, 0, 4, 0, 2, 4, 6, 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs);
|
||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp);
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp);
|
||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg);
|
||||
@@ -24,34 +24,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/i460_mux.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
|
||||
struct sockaddr;
|
||||
struct sockaddr_in;
|
||||
struct mgcp_conn;
|
||||
struct mgcp_conn_rtp;
|
||||
struct mgcp_endpoint;
|
||||
|
||||
/* Number of E1 subslots (different variants, not all useable at the same time) */
|
||||
#define MGCP_ENDP_E1_SUBSLOTS 15
|
||||
|
||||
#define LOGPENDP(endp, cat, level, fmt, args...) \
|
||||
LOGP(cat, level, "endpoint:%s " fmt, \
|
||||
endp ? endp->name : "none", \
|
||||
## args)
|
||||
|
||||
struct osmo_rtp_msg_ctx {
|
||||
int proto;
|
||||
struct mgcp_conn_rtp *conn_src;
|
||||
struct osmo_sockaddr *from_addr;
|
||||
struct sockaddr_in *from_addr;
|
||||
};
|
||||
|
||||
#define OSMO_RTP_MSG_CTX(MSGB) ((struct osmo_rtp_msg_ctx*)(MSGB)->cb)
|
||||
#define OSMO_RTP_MSG_CTX(MSGB) (*(struct osmo_rtp_msg_ctx**)&((MSGB)->dst))
|
||||
|
||||
osmo_static_assert(sizeof(((struct msgb*)0)->cb) >= sizeof(struct osmo_rtp_msg_ctx), osmo_rtp_msg_ctx_fits_in_msgb_cb);
|
||||
#define LOG_ENDP(endp, level, fmt, args...) \
|
||||
LOGP(DRTP, level, "%x@ " fmt, ENDPOINT_NUMBER(endp), ## args)
|
||||
|
||||
/* Callback type for RTP dispatcher functions (e.g mgcp_dispatch_rtp_bridge_cb, see below).
|
||||
* The OSMO_RTP_MSG_CTX() should be set appropriately on the msg. */
|
||||
* The fields OSMO_RTP_MSG_PROTO, OSMO_RTP_MSG_CONN_SRC, OSMO_RTP_MSG_FROM_ADDR should be set
|
||||
* appropriately on the msg. */
|
||||
typedef int (*mgcp_dispatch_rtp_cb) (struct msgb *msg);
|
||||
|
||||
/* Callback type for endpoint specific cleanup actions. This function
|
||||
@@ -76,7 +68,6 @@ struct mgcp_endpoint_type {
|
||||
/*! MGCP endpoint typeset */
|
||||
struct mgcp_endpoint_typeset {
|
||||
struct mgcp_endpoint_type rtp;
|
||||
struct mgcp_endpoint_type e1;
|
||||
};
|
||||
|
||||
/*! static MGCP endpoint typeset (pre-initalized, read-only) */
|
||||
@@ -85,9 +76,6 @@ extern const struct mgcp_endpoint_typeset ep_typeset;
|
||||
/*! MGCP endpoint model */
|
||||
struct mgcp_endpoint {
|
||||
|
||||
/*! Unique endpoint name, used for addressing via MGCP */
|
||||
char *name;
|
||||
|
||||
/*! Call identifier string (as supplied by the call agant) */
|
||||
char *callid;
|
||||
|
||||
@@ -97,8 +85,11 @@ struct mgcp_endpoint {
|
||||
/*! List of struct mgcp_conn, of the connections active on this endpoint */
|
||||
struct llist_head conns;
|
||||
|
||||
/*! Backpointer to the trunk this endpoint belongs to */
|
||||
struct mgcp_trunk *trunk;
|
||||
/*! Backpointer to the MGW configuration */
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
/*! Backpointer to the Trunk specific configuration */
|
||||
struct mgcp_trunk_config *tcfg;
|
||||
|
||||
/*! Endpoint properties (see above) */
|
||||
const struct mgcp_endpoint_type *type;
|
||||
@@ -109,34 +100,16 @@ struct mgcp_endpoint {
|
||||
/*! Last MGCP response (in case re-transmission is required) */
|
||||
char *last_response;
|
||||
|
||||
/*! Memorize if this endpoint was choosen by the MGW (wildcarded, true)
|
||||
* or if the user has choosen the particular endpoint explicitly. */
|
||||
bool wildcarded_req;
|
||||
|
||||
/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */
|
||||
uint32_t x_osmo_ign;
|
||||
|
||||
/* E1 specific */
|
||||
struct {
|
||||
struct osmo_i460_schan_desc scd;
|
||||
struct osmo_i460_subchan *schan;
|
||||
struct osmo_fsm_inst *trau_sync_fi;
|
||||
struct osmo_trau2rtp_state *trau_rtp_st;
|
||||
uint8_t last_amr_ft;
|
||||
struct mgcp_rtp_codec *last_codec;
|
||||
} e1;
|
||||
|
||||
};
|
||||
|
||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk, unsigned int index);
|
||||
/*! Extract endpoint number for a given endpoint */
|
||||
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
|
||||
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp);
|
||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid);
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp);
|
||||
bool mgcp_endp_is_wildcarded(const char *epname);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
||||
struct mgcp_config *cfg);
|
||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp);
|
||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
||||
const struct mgcp_trunk *trunk);
|
||||
|
||||
|
||||
343
include/osmocom/mgcp/mgcp_internal.h
Normal file
343
include/osmocom/mgcp/mgcp_internal.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/* MGCP Private Data */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/counter.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
||||
#define CI_UNUSED 0
|
||||
|
||||
/* FIXME: This this is only needed to compile the currently
|
||||
* broken OSMUX support. Remove when fixed */
|
||||
#define CONN_ID_BTS "0"
|
||||
#define CONN_ID_NET "1"
|
||||
|
||||
#define LOG_CONN(conn, level, fmt, args...) \
|
||||
LOGP(DRTP, level, "(%d@ I:%s) " fmt, \
|
||||
ENDPOINT_NUMBER((conn)->endp), (conn)->id, ## args)
|
||||
|
||||
#define LOG_CONN_RTP(conn_rtp, level, fmt, args...) \
|
||||
LOG_CONN(conn_rtp->conn, level, fmt, ## args)
|
||||
|
||||
enum mgcp_trunk_type {
|
||||
MGCP_TRUNK_VIRTUAL,
|
||||
MGCP_TRUNK_E1,
|
||||
};
|
||||
|
||||
struct mgcp_rtp_stream_state {
|
||||
uint32_t ssrc;
|
||||
uint16_t last_seq;
|
||||
uint32_t last_timestamp;
|
||||
struct rate_ctr *err_ts_ctr;
|
||||
int32_t last_tsdelta;
|
||||
uint32_t last_arrival_time;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_state {
|
||||
/* has this state structure been initialized? */
|
||||
int initialized;
|
||||
|
||||
struct {
|
||||
/* are we patching the SSRC value? */
|
||||
int patch_ssrc;
|
||||
/* original SSRC (to which we shall patch any different SSRC) */
|
||||
uint32_t orig_ssrc;
|
||||
/* offset to apply on the sequence number */
|
||||
int seq_offset;
|
||||
/* offset to apply on the timestamp number */
|
||||
int32_t timestamp_offset;
|
||||
} patch;
|
||||
|
||||
/* duration of a packet (FIXME: in which unit?) */
|
||||
uint32_t packet_duration;
|
||||
|
||||
struct mgcp_rtp_stream_state in_stream;
|
||||
struct mgcp_rtp_stream_state out_stream;
|
||||
|
||||
/* jitter and packet loss calculation */
|
||||
struct {
|
||||
int initialized;
|
||||
uint16_t base_seq;
|
||||
uint16_t max_seq;
|
||||
uint32_t ssrc;
|
||||
uint32_t jitter;
|
||||
int32_t transit;
|
||||
int cycles;
|
||||
} stats;
|
||||
|
||||
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
|
||||
};
|
||||
|
||||
struct mgcp_rtp_codec {
|
||||
uint32_t rate;
|
||||
int channels;
|
||||
uint32_t frame_duration_num;
|
||||
uint32_t frame_duration_den;
|
||||
|
||||
int payload_type;
|
||||
char *audio_name;
|
||||
char *subtype_name;
|
||||
};
|
||||
|
||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
||||
struct mgcp_rtp_end {
|
||||
/* local IP address of the RTP socket */
|
||||
struct in_addr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
|
||||
/* currently selected audio codec */
|
||||
struct mgcp_rtp_codec *codec;
|
||||
|
||||
/* array with assigned audio codecs to choose from (SDP) */
|
||||
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
|
||||
|
||||
/* number of assigned audio codecs (SDP) */
|
||||
unsigned int codecs_assigned;
|
||||
|
||||
/* per endpoint data */
|
||||
int frames_per_packet;
|
||||
uint32_t packet_duration_ms;
|
||||
int maximum_packet_time; /* -1: not set */
|
||||
char *fmtp_extra;
|
||||
/* are we transmitting packets (1) or dropping (0) outbound packets */
|
||||
int output_enabled;
|
||||
/* FIXME: This parameter can be set + printed, but is nowhere used! */
|
||||
int force_output_ptime;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
|
||||
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
|
||||
int force_aligned_timing;
|
||||
|
||||
/* Each end has a separate socket for RTP and RTCP */
|
||||
struct osmo_fd rtp;
|
||||
struct osmo_fd rtcp;
|
||||
|
||||
/* local UDP port number of the RTP socket; RTCP is +1 */
|
||||
int local_port;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
/* is this tap active (1) or not (0) */
|
||||
int enabled;
|
||||
/* IP/port to which we're forwarding the tapped data */
|
||||
struct sockaddr_in forward;
|
||||
};
|
||||
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
|
||||
/* Specific rtp connection type (see struct mgcp_conn_rtp) */
|
||||
enum mgcp_conn_rtp_type {
|
||||
MGCP_RTP_DEFAULT = 0,
|
||||
MGCP_OSMUX_BSC,
|
||||
MGCP_OSMUX_BSC_NAT,
|
||||
};
|
||||
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
struct mgcp_conn;
|
||||
|
||||
/* MGCP connection (RTP) */
|
||||
struct mgcp_conn_rtp {
|
||||
|
||||
/* Backpointer to conn struct */
|
||||
struct mgcp_conn *conn;
|
||||
|
||||
/* Specific connection type */
|
||||
enum mgcp_conn_rtp_type type;
|
||||
|
||||
/* Port status */
|
||||
struct mgcp_rtp_end end;
|
||||
|
||||
/* Sequence bits */
|
||||
struct mgcp_rtp_state state;
|
||||
|
||||
/* taps for the rtp connection; one per direction */
|
||||
struct mgcp_rtp_tap tap_in;
|
||||
struct mgcp_rtp_tap tap_out;
|
||||
|
||||
/* Osmux states (optional) */
|
||||
struct {
|
||||
/* Osmux state: disabled, activating, active */
|
||||
enum osmux_state state;
|
||||
/* Allocated Osmux circuit ID for this endpoint */
|
||||
int allocated_cid;
|
||||
/* Used Osmux circuit ID for this endpoint */
|
||||
uint8_t cid;
|
||||
/* handle to batch messages */
|
||||
struct osmux_in_handle *in;
|
||||
/* handle to unbatch messages */
|
||||
struct osmux_out_handle out;
|
||||
/* statistics */
|
||||
struct {
|
||||
uint32_t chunks;
|
||||
uint32_t octets;
|
||||
} stats;
|
||||
} osmux;
|
||||
|
||||
struct rate_ctr_group *rate_ctr_group;
|
||||
|
||||
struct osmo_iuup_cn *iuup;
|
||||
};
|
||||
|
||||
/*! Connection type, specifies which member of the union "u" in mgcp_conn
|
||||
* contains a useful connection description (currently only RTP) */
|
||||
enum mgcp_conn_type {
|
||||
MGCP_CONN_TYPE_RTP,
|
||||
};
|
||||
|
||||
/*! MGCP connection (untyped) */
|
||||
struct mgcp_conn {
|
||||
/*! list head */
|
||||
struct llist_head entry;
|
||||
|
||||
/*! Backpointer to the endpoint where the conn belongs to */
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/*! type of the connection (union) */
|
||||
enum mgcp_conn_type type;
|
||||
|
||||
/*! mode of the connection */
|
||||
enum mgcp_connection_mode mode;
|
||||
|
||||
/*! copy of the mode to restore the original setting (VTY) */
|
||||
enum mgcp_connection_mode mode_orig;
|
||||
|
||||
/*! connection id to identify the connection */
|
||||
char id[MGCP_CONN_ID_MAXLEN];
|
||||
|
||||
/*! human readable name (vty, logging) */
|
||||
char name[256];
|
||||
|
||||
/*! union with connection description */
|
||||
union {
|
||||
struct mgcp_conn_rtp rtp;
|
||||
} u;
|
||||
|
||||
/*! pointer to optional private data */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
|
||||
struct mgcp_endpoint_type;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Internal structure while parsing a request
|
||||
*/
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_config *cfg;
|
||||
struct mgcp_endpoint *endp;
|
||||
char *trans;
|
||||
char *save;
|
||||
};
|
||||
|
||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
|
||||
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
|
||||
struct mgcp_conn_rtp *conn_dst);
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
|
||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
|
||||
/* For transcoding we need to manage an in and an output that are connected */
|
||||
static inline int endp_back_channel(int endpoint)
|
||||
{
|
||||
return endpoint + 60;
|
||||
}
|
||||
|
||||
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index);
|
||||
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index);
|
||||
|
||||
char *get_lco_identifier(const char *options);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
int *payload_type,
|
||||
const char**audio_name,
|
||||
const char**fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
const uint32_t ssrc);
|
||||
|
||||
int mgcp_set_ip_tos(int fd, int tos);
|
||||
|
||||
enum {
|
||||
MGCP_DEST_NET = 0,
|
||||
MGCP_DEST_BTS,
|
||||
};
|
||||
|
||||
|
||||
#define MGCP_DUMMY_LOAD 0x23
|
||||
|
||||
|
||||
/**
|
||||
* SDP related information
|
||||
*/
|
||||
/* Assume audio frame length of 20ms */
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20
|
||||
#define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000
|
||||
#define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000
|
||||
#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1
|
||||
|
||||
#define PTYPE_UNDEFINED (-1)
|
||||
|
||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
||||
|
||||
void mgcp_patch_and_count(struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_state *state,
|
||||
struct mgcp_rtp_end *rtp_end,
|
||||
struct sockaddr_in *addr, struct msgb *msg);
|
||||
@@ -25,12 +25,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mgcp_conn;
|
||||
struct mgcp_parse_data;
|
||||
struct mgcp_endpoint;
|
||||
struct mgcp_trunk;
|
||||
|
||||
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
|
||||
|
||||
@@ -41,7 +39,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
|
||||
|
||||
int mgcp_parse_osmux_cid(const char *line);
|
||||
|
||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line);
|
||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line);
|
||||
|
||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid);
|
||||
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
|
||||
/* The following constant defines an RTP dummy payload that is used for
|
||||
* "UDP Hole Punching" (NAT) */
|
||||
static const char rtp_dummy_payload[] = { 0x23 };
|
||||
|
||||
/* Check if the data in a given message buffer matches the rtp dummy payload
|
||||
* defined above */
|
||||
#define mgcp_is_rtp_dummy_payload(msg) \
|
||||
(msgb_length(msg) == sizeof(rtp_dummy_payload) && \
|
||||
memcmp(msgb_data(msg), rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0)
|
||||
|
||||
#define RTP_BUF_SIZE 4096
|
||||
|
||||
struct mgcp_rtp_stream_state {
|
||||
uint32_t ssrc;
|
||||
uint16_t last_seq;
|
||||
uint32_t last_timestamp;
|
||||
struct rate_ctr *err_ts_ctr;
|
||||
int32_t last_tsdelta;
|
||||
uint32_t last_arrival_time;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_state {
|
||||
/* has this state structure been initialized? */
|
||||
int initialized;
|
||||
|
||||
struct {
|
||||
/* are we patching the SSRC value? */
|
||||
bool patch_ssrc;
|
||||
/* original SSRC (to which we shall patch any different SSRC) */
|
||||
uint32_t orig_ssrc;
|
||||
/* offset to apply on the sequence number */
|
||||
int seq_offset;
|
||||
/* offset to apply on the timestamp number */
|
||||
int32_t timestamp_offset;
|
||||
} patch;
|
||||
|
||||
/* duration of a packet (FIXME: in which unit?) */
|
||||
uint32_t packet_duration;
|
||||
|
||||
/* Note: These states are not continuously updated, they serve as an
|
||||
* information source to patch certain values in the RTP header. Do
|
||||
* not use this state if constantly updated data about the RTP stream
|
||||
* is needed. (see also mgcp_patch_and_count() */
|
||||
struct mgcp_rtp_stream_state in_stream;
|
||||
struct mgcp_rtp_stream_state out_stream;
|
||||
|
||||
/* jitter and packet loss calculation */
|
||||
struct {
|
||||
int initialized;
|
||||
uint16_t base_seq;
|
||||
uint16_t max_seq;
|
||||
uint32_t ssrc;
|
||||
uint32_t jitter;
|
||||
int32_t transit;
|
||||
int cycles;
|
||||
} stats;
|
||||
|
||||
/* Alternative values for RTP tx, in case no sufficient header
|
||||
* information is available so the header needs to be generated
|
||||
* locally (when just forwarding packets, the header of incoming
|
||||
* data is just re-used) */
|
||||
uint16_t alt_rtp_tx_sequence;
|
||||
uint32_t alt_rtp_tx_ssrc;
|
||||
|
||||
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
|
||||
};
|
||||
|
||||
struct mgcp_rtp_codec {
|
||||
uint32_t rate;
|
||||
int channels;
|
||||
uint32_t frame_duration_num;
|
||||
uint32_t frame_duration_den;
|
||||
|
||||
int payload_type;
|
||||
char audio_name[64];
|
||||
char subtype_name[64];
|
||||
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */
|
||||
struct mgcp_rtp_end {
|
||||
/* remote IP address of the RTP socket */
|
||||
struct osmo_sockaddr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
|
||||
/* currently selected audio codec */
|
||||
struct mgcp_rtp_codec *codec;
|
||||
|
||||
/* array with assigned audio codecs to choose from (SDP) */
|
||||
struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS];
|
||||
|
||||
/* number of assigned audio codecs (SDP) */
|
||||
unsigned int codecs_assigned;
|
||||
|
||||
/* per endpoint data */
|
||||
int frames_per_packet;
|
||||
uint32_t packet_duration_ms;
|
||||
int maximum_packet_time; /* -1: not set */
|
||||
char *fmtp_extra;
|
||||
/* are we transmitting packets (1) or dropping (0) outbound packets */
|
||||
int output_enabled;
|
||||
/* FIXME: This parameter can be set + printed, but is nowhere used! */
|
||||
int force_output_ptime;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
|
||||
/* should we perform align_rtp_timestamp_offset() (1) or not (0) */
|
||||
int force_aligned_timing;
|
||||
bool rfc5993_hr_convert;
|
||||
|
||||
/* Each end has a separate socket for RTP and RTCP */
|
||||
struct osmo_fd rtp;
|
||||
struct osmo_fd rtcp;
|
||||
|
||||
/* local UDP port number of the RTP socket; RTCP is +1 */
|
||||
int local_port;
|
||||
/* where the endpoint RTP connection binds to, set during CRCX and
|
||||
* possibly updated during MDCX */
|
||||
char local_addr[INET6_ADDRSTRLEN];
|
||||
};
|
||||
|
||||
bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end);
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
/* is this tap active (1) or not (0) */
|
||||
int enabled;
|
||||
/* IP/port to which we're forwarding the tapped data */
|
||||
struct osmo_sockaddr forward;
|
||||
};
|
||||
|
||||
struct mgcp_conn;
|
||||
|
||||
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr,
|
||||
struct msgb *msg, struct mgcp_conn_rtp *conn_src,
|
||||
struct mgcp_conn_rtp *conn_dst);
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg);
|
||||
void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
int mgcp_dispatch_e1_bridge_cb(struct msgb *msg);
|
||||
void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn);
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
void mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
void mgcp_patch_and_count(const struct mgcp_endpoint *endp,
|
||||
struct mgcp_rtp_state *state,
|
||||
struct mgcp_rtp_end *rtp_end,
|
||||
struct osmo_sockaddr *addr, struct msgb *msg);
|
||||
void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* payload processing default functions */
|
||||
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
|
||||
char *data, int *len, int buf_size);
|
||||
|
||||
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
|
||||
struct mgcp_conn_rtp *conn_dst,
|
||||
struct mgcp_conn_rtp *conn_src);
|
||||
|
||||
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_codec **codec,
|
||||
const char **fmtp_extra,
|
||||
struct mgcp_conn_rtp *conn);
|
||||
|
||||
/* internal RTP Annex A counting */
|
||||
void mgcp_rtp_annex_count(const struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
const uint16_t seq, const int32_t transit,
|
||||
const uint32_t ssrc, const bool marker_bit);
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* Internal structure while parsing a request */
|
||||
struct mgcp_parse_data {
|
||||
struct mgcp_config *cfg;
|
||||
char *epname;
|
||||
char *trans;
|
||||
char *save;
|
||||
};
|
||||
|
||||
/* Local connection options */
|
||||
struct mgcp_lco {
|
||||
char *string;
|
||||
char *codec;
|
||||
int pkt_period_min; /* time in ms */
|
||||
int pkt_period_max; /* time in ms */
|
||||
};
|
||||
|
||||
char *mgcp_debug_get_last_endpoint_name(void);
|
||||
|
||||
char *get_lco_identifier(const char *options);
|
||||
int check_local_cx_options(void *ctx, const char *options);
|
||||
|
||||
struct mgcp_rtp_end;
|
||||
struct mgcp_endpoint;
|
||||
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
|
||||
struct mgcp_rtp_end *rtp);
|
||||
|
||||
uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp,
|
||||
const struct mgcp_rtp_end *rtp);
|
||||
@@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* Global MCGP general rate counters */
|
||||
enum {
|
||||
MGCP_GENERAL_RX_MSGS_TOTAL,
|
||||
MGCP_GENERAL_RX_MSGS_RETRANSMITTED,
|
||||
MGCP_GENERAL_RX_MSGS_HANDLED,
|
||||
MGCP_GENERAL_RX_MSGS_UNHANDLED,
|
||||
MGCP_GENERAL_RX_FAIL_MSG_PARSE,
|
||||
MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP CRCX related rate counters */
|
||||
enum {
|
||||
MGCP_CRCX_SUCCESS,
|
||||
MGCP_CRCX_FAIL_BAD_ACTION,
|
||||
MGCP_CRCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_CRCX_FAIL_MISSING_CALLID,
|
||||
MGCP_CRCX_FAIL_INVALID_MODE,
|
||||
MGCP_CRCX_FAIL_LIMIT_EXCEEDED,
|
||||
MGCP_CRCX_FAIL_UNKNOWN_CALLID,
|
||||
MGCP_CRCX_FAIL_ALLOC_CONN,
|
||||
MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_CRCX_FAIL_START_RTP,
|
||||
MGCP_CRCX_FAIL_NO_OSMUX,
|
||||
MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_CRCX_FAIL_CODEC_NEGOTIATION,
|
||||
MGCP_CRCX_FAIL_BIND_PORT,
|
||||
MGCP_CRCX_FAIL_AVAIL,
|
||||
MGCP_CRCX_FAIL_CLAIM,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP MDCX related rate counters */
|
||||
enum {
|
||||
MGCP_MDCX_SUCCESS,
|
||||
MGCP_MDCX_FAIL_WILDCARD,
|
||||
MGCP_MDCX_FAIL_NO_CONN,
|
||||
MGCP_MDCX_FAIL_INVALID_CALLID,
|
||||
MGCP_MDCX_FAIL_INVALID_CONNID,
|
||||
MGCP_MDCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_MDCX_FAIL_NO_CONNID,
|
||||
MGCP_MDCX_FAIL_CONN_NOT_FOUND,
|
||||
MGCP_MDCX_FAIL_INVALID_MODE,
|
||||
MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS,
|
||||
MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
|
||||
MGCP_MDCX_FAIL_START_RTP,
|
||||
MGCP_MDCX_FAIL_AVAIL,
|
||||
};
|
||||
|
||||
/* Trunk-global MCGP DLCX related rate counters */
|
||||
enum {
|
||||
MGCP_DLCX_SUCCESS,
|
||||
MGCP_DLCX_FAIL_NO_CONN,
|
||||
MGCP_DLCX_FAIL_INVALID_CALLID,
|
||||
MGCP_DLCX_FAIL_INVALID_CONNID,
|
||||
MGCP_DLCX_FAIL_UNHANDLED_PARAM,
|
||||
MGCP_DLCX_FAIL_AVAIL,
|
||||
};
|
||||
|
||||
/* Trunk-global E1 related counters */
|
||||
enum {
|
||||
E1_I460_TRAU_RX_FAIL_CTR,
|
||||
E1_I460_TRAU_TX_FAIL_CTR,
|
||||
E1_I460_TRAU_MUX_EMPTY_CTR,
|
||||
};
|
||||
|
||||
/* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */
|
||||
|
||||
struct mgcp_ratectr_global {
|
||||
/* Rate counter group which contains stats for generic MGCP events. */
|
||||
struct rate_ctr_group *mgcp_general_ctr_group;
|
||||
};
|
||||
|
||||
struct mgcp_ratectr_trunk {
|
||||
/* Rate counter group which contains stats for processed CRCX commands. */
|
||||
struct rate_ctr_group *mgcp_crcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed MDCX commands. */
|
||||
struct rate_ctr_group *mgcp_mdcx_ctr_group;
|
||||
/* Rate counter group which contains stats for processed DLCX commands. */
|
||||
struct rate_ctr_group *mgcp_dlcx_ctr_group;
|
||||
/* Rate counter group which aggregates stats of individual RTP connections. */
|
||||
struct rate_ctr_group *all_rtp_conn_stats;
|
||||
/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
|
||||
struct rate_ctr_group *e1_stats;
|
||||
};
|
||||
|
||||
struct mgcp_config;
|
||||
struct mgcp_trunk;
|
||||
|
||||
int mgcp_ratectr_global_alloc(struct mgcp_config *cfg);
|
||||
void mgcp_ratectr_global_free(struct mgcp_config *cfg);
|
||||
int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk);
|
||||
void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk);
|
||||
|
||||
/* Trunk-global common stat items */
|
||||
enum {
|
||||
TRUNK_STAT_ENDPOINTS_TOTAL,
|
||||
TRUNK_STAT_ENDPOINTS_USED,
|
||||
};
|
||||
|
||||
struct mgcp_stat_trunk {
|
||||
/* Stat item group which contains general status values of the trunk. */
|
||||
struct osmo_stat_item_group *common;
|
||||
};
|
||||
|
||||
int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk);
|
||||
void mgcp_stat_trunk_free(struct mgcp_trunk *trunk);
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn);
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsm/i460_mux.h>
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/mgcp/mgcp_ratectr.h>
|
||||
|
||||
|
||||
#define LOGPTRUNK(trunk, cat, level, fmt, args...) \
|
||||
LOGP(cat, level, "trunk:%u " fmt, \
|
||||
trunk ? trunk->trunk_nr : 0, \
|
||||
## args)
|
||||
|
||||
enum mgcp_trunk_type {
|
||||
MGCP_TRUNK_VIRTUAL,
|
||||
MGCP_TRUNK_E1,
|
||||
};
|
||||
|
||||
extern const struct value_string mgcp_trunk_type_strs[];
|
||||
static inline const char *mgcp_trunk_type_strs_str(enum mgcp_trunk_type val)
|
||||
{ return get_value_string(mgcp_trunk_type_strs, val); }
|
||||
|
||||
struct mgcp_trunk {
|
||||
struct llist_head entry;
|
||||
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
unsigned int trunk_nr;
|
||||
enum mgcp_trunk_type trunk_type;
|
||||
|
||||
char *audio_fmtp_extra;
|
||||
int audio_send_ptime;
|
||||
int audio_send_name;
|
||||
|
||||
int no_audio_transcoding;
|
||||
|
||||
int omit_rtcp;
|
||||
int keepalive_interval;
|
||||
|
||||
/* RTP patching */
|
||||
int force_constant_ssrc; /* 0: don't, 1: once */
|
||||
int force_aligned_timing;
|
||||
bool rfc5993_hr_convert;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* timer */
|
||||
struct osmo_timer_list keepalive_timer;
|
||||
|
||||
/* When set, incoming RTP packets are not filtered
|
||||
* when ports and ip-address do not match (debug) */
|
||||
int rtp_accept_all;
|
||||
|
||||
unsigned int number_endpoints;
|
||||
struct mgcp_endpoint **endpoints;
|
||||
|
||||
/* rate counters and stat items to measure the trunks overall performance and health */
|
||||
struct mgcp_ratectr_trunk ratectr;
|
||||
struct mgcp_stat_trunk stats;
|
||||
|
||||
union {
|
||||
/* Virtual trunk specific */
|
||||
struct {
|
||||
unsigned int vty_number_endpoints;
|
||||
} v;
|
||||
/* E1 specific */
|
||||
struct {
|
||||
unsigned int vty_line_nr;
|
||||
bool ts_in_use[NUM_E1_TS-1];
|
||||
struct osmo_i460_timeslot i460_ts[NUM_E1_TS-1];
|
||||
/* Note: on an E1 line TS 0 is devoted to framing and
|
||||
* alignment and therefore only NUM_E1_TS-1 timeslots
|
||||
* are available for traffic. */
|
||||
} e1;
|
||||
};
|
||||
};
|
||||
|
||||
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
|
||||
int mgcp_trunk_equip(struct mgcp_trunk *trunk);
|
||||
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr);
|
||||
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname);
|
||||
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname);
|
||||
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num);
|
||||
|
||||
/* The virtual trunk is always created on trunk id 0 for historical reasons,
|
||||
* use this define constant as ID when allocating a virtual trunk. Other
|
||||
* trunks may be assigned with arbritrary id numbers */
|
||||
#define MGCP_VIRT_TRUNK_ID 0
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
struct mgcp_conn_rtp;
|
||||
@@ -14,21 +13,19 @@ enum {
|
||||
|
||||
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);
|
||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid);
|
||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn);
|
||||
struct in_addr *addr, uint16_t port);
|
||||
void osmux_disable_conn(struct mgcp_conn_rtp *conn);
|
||||
void osmux_allocate_cid(struct mgcp_conn_rtp *conn);
|
||||
void osmux_release_cid(struct mgcp_conn_rtp *conn);
|
||||
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn);
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
|
||||
|
||||
void osmux_cid_pool_get(uint8_t osmux_cid);
|
||||
int osmux_cid_pool_get_next(void);
|
||||
void osmux_cid_pool_put(uint8_t osmux_cid);
|
||||
bool osmux_cid_pool_allocated(uint8_t osmux_cid);
|
||||
int osmux_cid_pool_count_used(void);
|
||||
int osmux_get_cid(void);
|
||||
void osmux_put_cid(uint8_t osmux_cid);
|
||||
int osmux_used_cid(void);
|
||||
|
||||
enum osmux_state {
|
||||
OSMUX_STATE_DISABLED = 0, /* Osmux not being currently used by endp */
|
||||
OSMUX_STATE_NEGOTIATING, /* Osmux was locally requested in MGCP CRCX */
|
||||
OSMUX_STATE_ACTIVATING, /* Osmux was accepted in MGCP CRCX ACK. It can now be enabled by \ref osmux_enable_endpoint. */
|
||||
OSMUX_STATE_ENABLED, /* Osmux was initialized by \ref osmux_enable_endpoint and can process frames */
|
||||
};
|
||||
|
||||
@@ -6,7 +6,3 @@ enum mgcp_vty_node {
|
||||
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
TRUNK_NODE,
|
||||
};
|
||||
|
||||
enum mgw_vty_cmd_attr {
|
||||
MGW_CMD_ATTR_NEWCONN = 0,
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ BUILT_SOURCES = \
|
||||
|
||||
noinst_HEADERS = \
|
||||
mgcp_client_internal.h \
|
||||
mgcp_client_pool_internal.h \
|
||||
$(NULL)
|
||||
|
||||
mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <osmocom/mgcp_client/mgcp_common.h>
|
||||
|
||||
/* 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 "0.0.0.0"
|
||||
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 2727
|
||||
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
|
||||
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
|
||||
@@ -25,16 +25,7 @@ struct mgcp_client_conf {
|
||||
|
||||
/* By default, we are always addressing the MGW with e.g. 'rtpbridge/123@mgw'.
|
||||
* If this is nonempty, the contained name will be used instead of 'mgw'. */
|
||||
char endpoint_domain_name[MGCP_ENDPOINT_MAXLEN];
|
||||
|
||||
/* The user may configure certain endpoint names that are reset via DLCX
|
||||
* on startup. Usually this will be one wildcarded endpoint e.g.
|
||||
* 'rtpbridge/(wildcard)' or a number of specific E1 like e.g.
|
||||
* 'ds/e1-0/s-3/su16-4' */
|
||||
struct llist_head reset_epnames;
|
||||
|
||||
/* human readable name / description */
|
||||
char *description;
|
||||
char endpoint_domain_name[64];
|
||||
};
|
||||
|
||||
typedef unsigned int mgcp_trans_id_t;
|
||||
@@ -46,7 +37,7 @@ enum mgcp_codecs {
|
||||
CODEC_PCMA_8000_1 = 8,
|
||||
CODEC_G729_8000_1 = 18,
|
||||
CODEC_GSMEFR_8000_1 = 110,
|
||||
CODEC_GSMHR_8000_1 = 111,
|
||||
CODEC_GSMHR_8000_1 = 111,
|
||||
CODEC_AMR_8000_1 = 112,
|
||||
CODEC_AMRWB_16000_1 = 113,
|
||||
};
|
||||
@@ -56,10 +47,6 @@ enum mgcp_codecs {
|
||||
* this is an internal assumption that is made to avoid lookup tables.
|
||||
* The API-User should not rely on this coincidence! */
|
||||
|
||||
extern const struct value_string osmo_mgcpc_codec_names[];
|
||||
static inline const char *osmo_mgcpc_codec_name(enum mgcp_codecs val)
|
||||
{ return get_value_string(osmo_mgcpc_codec_names, val); }
|
||||
|
||||
/*! Structure to build a payload type map to allow the defiition custom payload
|
||||
* types. */
|
||||
struct ptmap {
|
||||
@@ -76,20 +63,18 @@ struct mgcp_response_head {
|
||||
char comment[MGCP_COMMENT_MAXLEN];
|
||||
char conn_id[MGCP_CONN_ID_MAXLEN];
|
||||
char endpoint[MGCP_ENDPOINT_MAXLEN];
|
||||
bool x_osmo_osmux_use;
|
||||
uint8_t x_osmo_osmux_cid;
|
||||
};
|
||||
|
||||
struct mgcp_response {
|
||||
char *body;
|
||||
struct mgcp_response_head head;
|
||||
uint16_t audio_port;
|
||||
char audio_ip[INET6_ADDRSTRLEN];
|
||||
char audio_ip[INET_ADDRSTRLEN];
|
||||
unsigned int ptime;
|
||||
enum mgcp_codecs codecs[MGCP_MAX_CODECS];
|
||||
unsigned int codecs_len;
|
||||
struct ptmap ptmap[MGCP_MAX_CODECS];
|
||||
unsigned int ptmap_len;
|
||||
unsigned int ptmap_len;
|
||||
};
|
||||
|
||||
enum mgcp_verb {
|
||||
@@ -106,7 +91,6 @@ enum mgcp_verb {
|
||||
#define MGCP_MSG_PRESENCE_AUDIO_IP 0x0008
|
||||
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
|
||||
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
|
||||
#define MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID 0x4000
|
||||
#define MGCP_MSG_PRESENCE_X_OSMO_IGN 0x8000
|
||||
|
||||
struct mgcp_msg {
|
||||
@@ -125,10 +109,6 @@ struct mgcp_msg {
|
||||
struct ptmap ptmap[MGCP_MAX_CODECS];
|
||||
unsigned int ptmap_len;
|
||||
uint32_t x_osmo_ign;
|
||||
bool x_osmo_osmux_use;
|
||||
int x_osmo_osmux_cid; /* -1 is wildcard */
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
|
||||
@@ -139,17 +119,13 @@ struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp);
|
||||
struct mgcp_client *mgcp_client_init(void *ctx,
|
||||
struct mgcp_client_conf *conf);
|
||||
int mgcp_client_connect(struct mgcp_client *mgcp);
|
||||
int mgcp_client_connect2(struct mgcp_client *mgcp, unsigned int retry_n_ports);
|
||||
void mgcp_client_disconnect(struct mgcp_client *mgcp);
|
||||
|
||||
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp);
|
||||
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp);
|
||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp) OSMO_DEPRECATED("deprecated, returns 0");
|
||||
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp);
|
||||
|
||||
const char *mgcp_client_endpoint_domain(const struct mgcp_client *mgcp);
|
||||
const char *mgcp_client_rtpbridge_wildcard(const struct mgcp_client *mgcp);
|
||||
const char *mgcp_client_e1_epname(void *ctx, const struct mgcp_client *mgcp, uint8_t trunk_id, uint8_t ts,
|
||||
uint8_t rate, uint8_t offset);
|
||||
|
||||
/* Invoked when an MGCP response is received or sending failed. When the
|
||||
* response is passed as NULL, this indicates failure during transmission. */
|
||||
@@ -172,9 +148,7 @@ static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
|
||||
}
|
||||
|
||||
enum mgcp_codecs map_str_to_codec(const char *str);
|
||||
unsigned int map_codec_to_pt(const struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
unsigned int map_codec_to_pt(struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
enum mgcp_codecs codec);
|
||||
enum mgcp_codecs map_pt_to_codec(struct ptmap *ptmap, unsigned int ptmap_len,
|
||||
unsigned int pt);
|
||||
|
||||
const char *mgcp_client_name(const struct mgcp_client *mgcp);
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* FSM to manage multiple connections of an MGW endpoint */
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client_fsm.h>
|
||||
|
||||
#define LOG_MGCPC_EP(ep, level, fmt, args...) do { \
|
||||
LOGPFSML(ep->fi, level, "%s " fmt, \
|
||||
osmo_mgcpc_ep_name(ep), ## args); \
|
||||
} while(0)
|
||||
|
||||
struct osmo_mgcpc_ep;
|
||||
struct osmo_mgcpc_ep_ci;
|
||||
struct osmo_tdef;
|
||||
|
||||
struct osmo_mgcpc_ep *osmo_mgcpc_ep_alloc(struct osmo_fsm_inst *parent, uint32_t parent_term_event,
|
||||
struct mgcp_client *mgcp_client,
|
||||
const struct osmo_tdef *T_defs,
|
||||
const char *fsm_id,
|
||||
const char *endpoint_str_fmt, ...);
|
||||
|
||||
struct osmo_mgcpc_ep_ci *osmo_mgcpc_ep_ci_add(struct osmo_mgcpc_ep *ep, const char *label_fmt, ...);
|
||||
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
|
||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(const struct osmo_mgcpc_ep_ci *ci, struct sockaddr_storage *dest);
|
||||
bool osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(const struct osmo_mgcpc_ep_ci *ci, uint8_t* cid);
|
||||
|
||||
const struct mgcp_conn_peer *osmo_mgcpc_ep_ci_get_remote_rtp_info(const struct osmo_mgcpc_ep_ci *ci);
|
||||
|
||||
void osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
|
||||
enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
|
||||
struct osmo_fsm_inst *notify,
|
||||
uint32_t event_success, uint32_t event_failure,
|
||||
void *notify_data);
|
||||
|
||||
void osmo_mgcpc_ep_cancel_notify(struct osmo_mgcpc_ep *ep, struct osmo_fsm_inst *notify);
|
||||
struct osmo_mgcpc_ep *osmo_mgcpc_ep_ci_ep(struct osmo_mgcpc_ep_ci *ci);
|
||||
|
||||
/*! Dispatch a DLCX for the given connection.
|
||||
* \param ci Connection identifier as obtained from osmo_mgcpc_ep_ci_add().
|
||||
*/
|
||||
static inline void osmo_mgcpc_ep_ci_dlcx(struct osmo_mgcpc_ep_ci *ci)
|
||||
{
|
||||
osmo_mgcpc_ep_ci_request(ci, MGCP_VERB_DLCX, NULL, NULL, 0, 0, NULL);
|
||||
}
|
||||
|
||||
void osmo_mgcpc_ep_clear(struct osmo_mgcpc_ep *ep);
|
||||
|
||||
const char *osmo_mgcpc_ep_name(const struct osmo_mgcpc_ep *ep);
|
||||
const char *osmo_mgcpc_ep_ci_name(const struct osmo_mgcpc_ep_ci *ci);
|
||||
const char *osmo_mgcpc_ep_ci_id(const struct osmo_mgcpc_ep_ci *ci);
|
||||
struct mgcp_client *osmo_mgcpc_ep_client(const struct osmo_mgcpc_ep *ep);
|
||||
|
||||
extern const struct value_string osmo_mgcp_verb_names[];
|
||||
static inline const char *osmo_mgcp_verb_name(enum mgcp_verb val)
|
||||
{ return get_value_string(osmo_mgcp_verb_names, val); }
|
||||
@@ -8,14 +8,14 @@
|
||||
* (either remote or local). It is used to pass parameters (local) to the FSM
|
||||
* and get responses (remote) from the FSM as pointer attached to the FSM
|
||||
* event.
|
||||
*
|
||||
*
|
||||
* When modifiying a connection, the endpoint and call_id members may be left
|
||||
* unpopulated. The call_id field is ignored in this case. If an endpoint
|
||||
* identifier is supplied it is checked against the internal state to make
|
||||
* sure it is correct. */
|
||||
struct mgcp_conn_peer {
|
||||
/*! RTP connection IP-Address (optional, string e.g. "127.0.0.1") */
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
|
||||
/*! RTP connection IP-Port (optional) */
|
||||
uint16_t port;
|
||||
@@ -47,20 +47,6 @@ struct mgcp_conn_peer {
|
||||
* known to issue incoherent or unknown CallIDs / to issue CRCX commands with a different domain
|
||||
* name than the BSC. An OsmoMGW will then ignore these and not fail on mismatches. */
|
||||
uint32_t x_osmo_ign;
|
||||
|
||||
/*! send 'X-Osmux: %d' header (or "*" as wildcard). */
|
||||
bool x_osmo_osmux_use;
|
||||
/*! -1 means send wildcard. */
|
||||
int x_osmo_osmux_cid;
|
||||
|
||||
/*! If left MGCP_CONN_NONE, use MGCP_CONN_RECV_ONLY or MGCP_CONN_RECV_SEND, depending on whether an audio RTP
|
||||
* address is set. If != MGCP_CONN_NONE, force this conn mode. */
|
||||
enum mgcp_connection_mode conn_mode;
|
||||
|
||||
/*! If the codec requires additional format parameters (fmtp), those cann be set here, see also
|
||||
* mgcp_common.h */
|
||||
bool param_present;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm_inst *parent_fi, uint32_t parent_term_evt,
|
||||
@@ -69,6 +55,3 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
|
||||
void mgcp_conn_delete(struct osmo_fsm_inst *fi);
|
||||
|
||||
const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi);
|
||||
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi);
|
||||
|
||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info);
|
||||
|
||||
@@ -4,19 +4,13 @@
|
||||
|
||||
#define MSGB_CB_MGCP_TRANS_ID 0
|
||||
|
||||
/* Struct that holds one endpoint name */
|
||||
struct reset_ep {
|
||||
struct llist_head list;
|
||||
char name[MGCP_ENDPOINT_MAXLEN];
|
||||
};
|
||||
|
||||
struct mgcp_client {
|
||||
struct mgcp_client_conf actual;
|
||||
uint32_t remote_addr;
|
||||
struct osmo_wqueue wq;
|
||||
mgcp_trans_id_t next_trans_id;
|
||||
struct llist_head responses_pending;
|
||||
struct llist_head inuse_endpoints;
|
||||
struct mgcp_client_pool *pool;
|
||||
};
|
||||
|
||||
struct mgcp_inuse_endpoint {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct mgcp_client;
|
||||
struct mgcp_client_pool;
|
||||
|
||||
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);
|
||||
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);
|
||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool);
|
||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client);
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* Struct to handle a member of a pool of MGWs. */
|
||||
struct mgcp_client_pool_member {
|
||||
struct llist_head list;
|
||||
|
||||
/* Reference number assinged by VTY. This number is used to manage the pool from the VTY and to identify it in
|
||||
* the log. */
|
||||
unsigned int nr;
|
||||
|
||||
/* MGCP client configuration, this is not the running configuration, when mgcp_client_init() is executed, a
|
||||
* copy of this config is created. */
|
||||
struct mgcp_client_conf conf;
|
||||
|
||||
/* MGCP client descriptor, will be automatically allocated when mgcp_client_pool_connect() is called. (the MGCP
|
||||
* client is connected when this pointer is populated) */
|
||||
struct mgcp_client *client;
|
||||
|
||||
/* A pool member may be set as 'blocked' from the VTY, this means that the pool member may still work and serve
|
||||
* ongoing calls, but it won't be picked from the pool anymore. */
|
||||
bool blocked;
|
||||
|
||||
/* Reference counter to count how often this pool member is currently picked. */
|
||||
unsigned int refcount;
|
||||
};
|
||||
|
||||
/* 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 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);
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -9,7 +9,6 @@ AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -21,7 +20,7 @@ AM_LDFLAGS = \
|
||||
|
||||
# This is not at all related to the release version, but a range of supported
|
||||
# API versions. Read TODO_RELEASE in the source tree's root!
|
||||
MGCP_CLIENT_LIBVERSION=9:0:0
|
||||
MGCP_CLIENT_LIBVERSION=4:0:1
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libosmo-mgcp-client.la \
|
||||
@@ -31,8 +30,6 @@ libosmo_mgcp_client_la_SOURCES = \
|
||||
mgcp_client.c \
|
||||
mgcp_client_vty.c \
|
||||
mgcp_client_fsm.c \
|
||||
mgcp_client_endpoint_fsm.c \
|
||||
mgcp_client_pool.c \
|
||||
$(NULL)
|
||||
|
||||
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,6 @@
|
||||
#include <osmocom/core/byteswap.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
|
||||
/* Context information, this is attached to the priv pointer of the FSM and
|
||||
* is also handed back when dispatcheing events to the parent FSM. This is
|
||||
@@ -115,23 +114,16 @@ static void make_crcx_msg(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info
|
||||
.conn_mode = MGCP_CONN_RECV_ONLY,
|
||||
.ptime = info->ptime,
|
||||
.codecs_len = info->codecs_len,
|
||||
.ptmap_len = info->ptmap_len,
|
||||
.param_present = info->param_present
|
||||
.ptmap_len = info->ptmap_len
|
||||
};
|
||||
osmo_strlcpy(mgcp_msg->endpoint, info->endpoint, MGCP_ENDPOINT_MAXLEN);
|
||||
memcpy(mgcp_msg->codecs, info->codecs, sizeof(mgcp_msg->codecs));
|
||||
memcpy(mgcp_msg->ptmap, info->ptmap, sizeof(mgcp_msg->ptmap));
|
||||
memcpy(&mgcp_msg->param, &info->param, sizeof(mgcp_msg->param));
|
||||
|
||||
if (info->x_osmo_ign) {
|
||||
mgcp_msg->x_osmo_ign = info->x_osmo_ign;
|
||||
mgcp_msg->presence |= MGCP_MSG_PRESENCE_X_OSMO_IGN;
|
||||
}
|
||||
|
||||
if (info->x_osmo_osmux_use) {
|
||||
mgcp_msg->x_osmo_osmux_cid = info->x_osmo_osmux_cid;
|
||||
mgcp_msg->presence |= MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
|
||||
@@ -142,13 +134,6 @@ static void add_audio(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *info)
|
||||
mgcp_msg->conn_mode = MGCP_CONN_RECV_SEND;
|
||||
}
|
||||
|
||||
static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer)
|
||||
{
|
||||
enum mgcp_connection_mode conn_mode = peer->conn_mode;
|
||||
if (conn_mode != MGCP_CONN_NONE)
|
||||
mgcp_msg->conn_mode = conn_mode;
|
||||
}
|
||||
|
||||
static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
||||
{
|
||||
struct mgcp_msg mgcp_msg;
|
||||
@@ -164,20 +149,11 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx)
|
||||
.audio_port = mgcp_ctx->conn_peer_local.port,
|
||||
.ptime = mgcp_ctx->conn_peer_local.ptime,
|
||||
.codecs_len = mgcp_ctx->conn_peer_local.codecs_len,
|
||||
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len,
|
||||
.param_present = mgcp_ctx->conn_peer_local.param_present
|
||||
.ptmap_len = mgcp_ctx->conn_peer_local.ptmap_len
|
||||
};
|
||||
osmo_strlcpy(mgcp_msg.endpoint, mgcp_ctx->conn_peer_remote.endpoint, MGCP_ENDPOINT_MAXLEN);
|
||||
memcpy(mgcp_msg.codecs, mgcp_ctx->conn_peer_local.codecs, sizeof(mgcp_msg.codecs));
|
||||
memcpy(mgcp_msg.ptmap, mgcp_ctx->conn_peer_local.ptmap, sizeof(mgcp_msg.ptmap));
|
||||
memcpy(&mgcp_msg.param, &mgcp_ctx->conn_peer_local.param, sizeof(mgcp_ctx->conn_peer_local.param));
|
||||
|
||||
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
|
||||
if (mgcp_ctx->conn_peer_local.x_osmo_osmux_use) {
|
||||
mgcp_msg.x_osmo_osmux_cid = mgcp_ctx->conn_peer_local.x_osmo_osmux_cid;
|
||||
mgcp_msg.presence |= MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID;
|
||||
}
|
||||
|
||||
/* Note: We take the endpoint and the call_id from the remote
|
||||
* connection info, because we can be confident that the
|
||||
@@ -223,8 +199,6 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
make_crcx_msg(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
if (mgcp_ctx->conn_peer_local.port)
|
||||
add_audio(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local);
|
||||
|
||||
msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg);
|
||||
OSMO_ASSERT(msg);
|
||||
|
||||
@@ -252,18 +226,6 @@ const char *mgcp_conn_get_ci(struct osmo_fsm_inst *fi)
|
||||
return mgcp_ctx->conn_id;
|
||||
}
|
||||
|
||||
/* Get the mgcp_client that is used with this mgcp_client_fsm instance */
|
||||
struct mgcp_client *mgcp_conn_get_client(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
struct mgcp_ctx *mgcp_ctx;
|
||||
|
||||
if (!fi)
|
||||
return NULL;
|
||||
|
||||
mgcp_ctx = fi->priv;
|
||||
return mgcp_ctx->mgcp;
|
||||
}
|
||||
|
||||
static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
|
||||
{
|
||||
struct osmo_fsm_inst *fi = priv;
|
||||
@@ -293,11 +255,6 @@ static void mgw_crcx_resp_cb(struct mgcp_response *r, void *priv)
|
||||
return;
|
||||
}
|
||||
LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
|
||||
if (r->head.x_osmo_osmux_use) {
|
||||
LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded using Osmux %u\n", r->head.x_osmo_osmux_cid);
|
||||
mgcp_ctx->conn_peer_remote.x_osmo_osmux_use = true;
|
||||
mgcp_ctx->conn_peer_remote.x_osmo_osmux_cid = r->head.x_osmo_osmux_cid;
|
||||
}
|
||||
|
||||
osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
|
||||
mgcp_ctx->conn_peer_remote.port = r->audio_port;
|
||||
@@ -417,12 +374,6 @@ static void mgw_mdcx_resp_cb(struct mgcp_response *r, void *priv)
|
||||
}
|
||||
LOGPFSML(fi, LOGL_DEBUG, "MGW/MDCX: MGW responded with address %s:%u\n", r->audio_ip, r->audio_port);
|
||||
|
||||
if (r->head.x_osmo_osmux_use) {
|
||||
LOGPFSML(fi, LOGL_DEBUG, "MGW/CRCX: MGW responded using Osmux %u\n", r->head.x_osmo_osmux_cid);
|
||||
mgcp_ctx->conn_peer_remote.x_osmo_osmux_use = true;
|
||||
mgcp_ctx->conn_peer_remote.x_osmo_osmux_cid = r->head.x_osmo_osmux_cid;
|
||||
}
|
||||
|
||||
osmo_strlcpy(mgcp_ctx->conn_peer_remote.addr, r->audio_ip, sizeof(mgcp_ctx->conn_peer_remote.addr));
|
||||
mgcp_ctx->conn_peer_remote.port = r->audio_port;
|
||||
|
||||
@@ -533,17 +484,13 @@ static void fsm_cleanup_cb(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause ca
|
||||
/* Should the FSM be terminated while there are still open connections
|
||||
* on the MGW, we send an unconditional DLCX to terminate the
|
||||
* connection. This is not the normal case. The user should always use
|
||||
* mgcp_conn_delete() to instruct the FSM to perform a graceful exit.
|
||||
* If in ST_DLCX_RESP, a DLCX was already sent and we did not get a
|
||||
* response. No point in sending another one. */
|
||||
if (fi->state != ST_DLCX_RESP && strlen(mgcp_ctx->conn_id)) {
|
||||
LOGPFSML(fi, LOGL_INFO, "Conn cleanup, sending DLCX for %s %s\n", mgcp_ctx->conn_peer_remote.endpoint,
|
||||
mgcp_ctx->conn_id);
|
||||
* mgcp_conn_delete() to instruct the FSM to perform a graceful exit */
|
||||
if (strlen(mgcp_ctx->conn_id)) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"MGW/DLCX: abrupt FSM termination with connections still present, sending unconditional DLCX...\n");
|
||||
msg = make_dlcx_msg(mgcp_ctx);
|
||||
if (!msg)
|
||||
LOGPFSML(fi, LOGL_ERROR, "MGW/DLCX: Error composing DLCX message\n");
|
||||
else
|
||||
mgcp_client_tx(mgcp, msg, NULL, NULL);
|
||||
OSMO_ASSERT(msg);
|
||||
mgcp_client_tx(mgcp, msg, NULL, NULL);
|
||||
}
|
||||
|
||||
talloc_free(mgcp_ctx);
|
||||
@@ -608,7 +555,6 @@ static struct osmo_fsm fsm_mgcp_client = {
|
||||
.timer_cb = fsm_timeout_cb,
|
||||
.cleanup = fsm_cleanup_cb,
|
||||
.event_names = fsm_mgcp_client_evt_names,
|
||||
.log_subsys = DLMGCP,
|
||||
};
|
||||
|
||||
/*! allocate FSM, and create a new connection on the MGW.
|
||||
@@ -622,19 +568,24 @@ struct osmo_fsm_inst *mgcp_conn_create(struct mgcp_client *mgcp, struct osmo_fsm
|
||||
uint32_t parent_term_evt, uint32_t parent_evt, struct mgcp_conn_peer *conn_peer)
|
||||
{
|
||||
struct mgcp_ctx *mgcp_ctx;
|
||||
static bool fsm_registered = false;
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct in6_addr ip_test;
|
||||
|
||||
struct in_addr ip_test;
|
||||
|
||||
OSMO_ASSERT(parent_fi);
|
||||
OSMO_ASSERT(mgcp);
|
||||
OSMO_ASSERT(conn_peer);
|
||||
|
||||
/* Check if IP/Port information in conn info makes sense */
|
||||
if (conn_peer->port && inet_pton(osmo_ip_str_type(conn_peer->addr),
|
||||
conn_peer->addr, &ip_test) != 1)
|
||||
if (conn_peer->port && inet_aton(conn_peer->addr, &ip_test) == 0)
|
||||
return NULL;
|
||||
|
||||
/* Register the fsm description (if not already done) */
|
||||
if (fsm_registered == false) {
|
||||
osmo_fsm_register(&fsm_mgcp_client);
|
||||
fsm_registered = true;
|
||||
}
|
||||
|
||||
/* Allocate and configure a new fsm instance */
|
||||
fi = osmo_fsm_inst_alloc_child(&fsm_mgcp_client, parent_fi, parent_term_evt);
|
||||
OSMO_ASSERT(fi);
|
||||
@@ -662,7 +613,7 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
|
||||
{
|
||||
OSMO_ASSERT(fi);
|
||||
struct mgcp_ctx *mgcp_ctx = fi->priv;
|
||||
struct in6_addr ip_test;
|
||||
struct in_addr ip_test;
|
||||
|
||||
OSMO_ASSERT(mgcp_ctx);
|
||||
OSMO_ASSERT(conn_peer);
|
||||
@@ -686,8 +637,8 @@ int mgcp_conn_modify(struct osmo_fsm_inst *fi, uint32_t parent_evt, struct mgcp_
|
||||
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, port == 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (inet_pton(osmo_ip_str_type(conn_peer->addr), conn_peer->addr, &ip_test) != 1) {
|
||||
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address %s\n", conn_peer->addr);
|
||||
if (inet_aton(conn_peer->addr, &ip_test) == 0) {
|
||||
LOGPFSML(fi, LOGL_ERROR, "Cannot MDCX, IP address == 0.0.0.0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -719,11 +670,8 @@ void mgcp_conn_delete(struct osmo_fsm_inst *fi)
|
||||
|
||||
OSMO_ASSERT(mgcp_ctx);
|
||||
|
||||
if (fi->proc.terminating)
|
||||
return;
|
||||
|
||||
/* Unlink FSM from parent, set the struct mgcp_client as new talloc ctx. */
|
||||
osmo_fsm_inst_unlink_parent(fi, mgcp_ctx->mgcp);
|
||||
/* Unlink FSM from parent */
|
||||
osmo_fsm_inst_unlink_parent(fi, NULL);
|
||||
|
||||
/* An error situation where the parent FSM must be killed immediately
|
||||
* may lead into a situation where the DLCX can not be executed right
|
||||
@@ -737,30 +685,3 @@ void mgcp_conn_delete(struct osmo_fsm_inst *fi)
|
||||
}
|
||||
osmo_fsm_inst_dispatch(fi, EV_DLCX, mgcp_ctx);
|
||||
}
|
||||
|
||||
const char *osmo_mgcpc_conn_peer_name(const struct mgcp_conn_peer *info)
|
||||
{
|
||||
/* I'd be fine with a smaller buffer and accept truncation, but gcc possibly refuses to build if
|
||||
* this buffer is too small. */
|
||||
static char buf[1024];
|
||||
|
||||
if (!info)
|
||||
return "NULL";
|
||||
|
||||
if (info->endpoint[0]
|
||||
&& info->addr[0])
|
||||
snprintf(buf, sizeof(buf), "%s:%s:%u",
|
||||
info->endpoint, info->addr, info->port);
|
||||
else if (info->endpoint[0])
|
||||
snprintf(buf, sizeof(buf), "%s", info->endpoint);
|
||||
else if (info->addr[0])
|
||||
snprintf(buf, sizeof(buf), "%s:%u", info->addr, info->port);
|
||||
else
|
||||
return "empty";
|
||||
return buf;
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void osmo_mgcp_client_fsm_init()
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&fsm_mgcp_client) == 0);
|
||||
}
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
/* (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Philipp Maier
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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/mgcp_client/mgcp_client.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.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define LOGPPMGW(pool_member, level, fmt, 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
|
||||
* 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. */
|
||||
struct mgcp_client_pool *mgcp_client_pool_alloc(void *talloc_ctx)
|
||||
{
|
||||
struct mgcp_client_pool *pool;
|
||||
|
||||
pool = talloc_zero(talloc_ctx, struct mgcp_client_pool);
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
INIT_LLIST_HEAD(&pool->pool);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
/*! Initialize and connect an mcgp client pool.
|
||||
* \param[in,out] mgcp MGCP client pool descriptor.
|
||||
* \returns number of successfully initialized pool members. */
|
||||
unsigned int mgcp_client_pool_connect(struct mgcp_client_pool *pool)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
unsigned int pool_members_initialized = 0;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
|
||||
/* 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");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set backpointer so that we can detect later that this MGCP client is managed
|
||||
* by this pool. */
|
||||
pool_member->client->pool = pool;
|
||||
|
||||
/* Connect client */
|
||||
if (mgcp_client_connect2(pool_member->client, 0)) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGCP client connect failed at (%s:%u)\n",
|
||||
pool_member->conf.remote_addr, pool_member->conf.remote_port);
|
||||
talloc_free(pool_member->client);
|
||||
pool_member->client = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
pool_members_initialized++;
|
||||
}
|
||||
|
||||
return pool_members_initialized;
|
||||
}
|
||||
|
||||
/*! register a single mgcp_client instance to the pool.
|
||||
* \param[out] pool MGCP client pool descriptor.
|
||||
* \param[in] mgcp MGCP client descriptor. */
|
||||
void mgcp_client_pool_register_single(struct mgcp_client_pool *pool, struct mgcp_client *mgcp_client)
|
||||
{
|
||||
/*! Some applications still support the non-pooled MGW VTY configuration variant provided by
|
||||
* mgcp_client_vty_init(). If this is the case the mgcp_client instance created by mgcp_client_init()
|
||||
* can be registered here so that it will appear as if it were part of the pool. When the user actively
|
||||
* configures MGW pool members, the MGCP client registered here will be ignored. (The registration of
|
||||
* multiple singe mgcp_client instances is not possible.) */
|
||||
pool->mgcp_client_single = mgcp_client;
|
||||
}
|
||||
|
||||
/* 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). */
|
||||
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_picked = NULL;
|
||||
unsigned int n_pool_members = llist_count(&pool->pool);
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
if (pool_member->blocked == false && pool_member->client) {
|
||||
if (!pool_member_picked)
|
||||
pool_member_picked = pool_member;
|
||||
else if (pool_member_picked->refcount > pool_member->refcount)
|
||||
pool_member_picked = pool_member;
|
||||
} else {
|
||||
LOGPPMGW(pool_member, LOGL_DEBUG, "MGW pool has %u members -- MGW %u is unusable\n", n_pool_members,
|
||||
pool_member->nr);
|
||||
}
|
||||
}
|
||||
|
||||
if (pool_member_picked) {
|
||||
LOGPPMGW(pool_member_picked, LOGL_DEBUG, "MGW pool has %u members -- using MGW %u (active calls: %u)\n",
|
||||
n_pool_members, pool_member_picked->nr, pool_member_picked->refcount);
|
||||
return pool_member_picked;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"MGW pool has %u members, but no functional MGW pool member found -- check configuration!\n",
|
||||
n_pool_members);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! get an MGCP client from the pool (increment reference counter).
|
||||
* \param[in,out] pool MGCP client pool descriptor.
|
||||
* \returns MGCP client descriptor, NULL if no member was found (empty pool). */
|
||||
struct mgcp_client *mgcp_client_pool_get(struct mgcp_client_pool *pool)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
/*! When an MGCP client is taken from the pool it is still available for other calls. In fact only a reference
|
||||
* counter is incremented to keep track on how many references to a specific MGCP client are currently used
|
||||
* by the application code. */
|
||||
|
||||
/* When the pool is empty, return a single MGCP client if it is registered. */
|
||||
if (llist_empty(&pool->pool) && pool->mgcp_client_single) {
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "MGW pool is empty -- using (single) MGW %s\n",
|
||||
mgcp_client_name(pool->mgcp_client_single));
|
||||
return pool->mgcp_client_single;
|
||||
}
|
||||
|
||||
/* Abort when the pool is empty */
|
||||
if (llist_empty(&pool->pool)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGW pool is empty -- no MGW available!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pick a suitable pool member */
|
||||
pool_member = mgcp_client_pool_pick(pool);
|
||||
if (pool_member) {
|
||||
pool_member->refcount++;
|
||||
return pool_member->client;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! put an MGCP client back into the pool (decrement reference counter).
|
||||
* \param[in,out] pool MGCP client pool descriptor.
|
||||
* \param[in] mgcp MGCP client descriptor.
|
||||
*
|
||||
* This function is able to detect automatically to which pool the mgcp_client belongs. If the mgcp_client does
|
||||
* not belong to a pool at all, the function call will have no effect. */
|
||||
void mgcp_client_pool_put(struct mgcp_client *mgcp_client)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
struct mgcp_client_pool *pool;
|
||||
|
||||
if (!mgcp_client)
|
||||
return;
|
||||
|
||||
if (mgcp_client->pool)
|
||||
pool = mgcp_client->pool;
|
||||
else
|
||||
return;
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
if (pool_member->client == mgcp_client) {
|
||||
if (pool_member->refcount == 0) {
|
||||
LOGPPMGW(pool_member, LOGL_ERROR, "MGW pool member has invalid refcount\n");
|
||||
return;
|
||||
}
|
||||
pool_member->refcount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,47 +24,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <talloc.h>
|
||||
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <osmocom/mgcp_client/mgcp_client.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_internal.h>
|
||||
#include <osmocom/mgcp_client/mgcp_client_pool_internal.h>
|
||||
|
||||
#define MGW_STR MGCP_CLIENT_MGW_STR
|
||||
|
||||
/* Only common (non-pooled) VTY connands will use this talloc context. All
|
||||
* pooled VTY commands will use the pool (global_mgcp_client_pool) as
|
||||
* talloc context. */
|
||||
static void *global_mgcp_client_ctx = NULL;
|
||||
|
||||
/* MGCP Client configuration used with mgcp_client_vty_init(). (This pointer
|
||||
* points to user provided memory, so it cannot be used as talloc context.) */
|
||||
static struct mgcp_client_conf *global_mgcp_client_conf = NULL;
|
||||
|
||||
/* Pointer to the MGCP pool that is managed by mgcp_client_pool_vty_init() */
|
||||
static struct mgcp_client_pool *global_mgcp_client_pool = NULL;
|
||||
|
||||
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)
|
||||
return vty->index;
|
||||
else
|
||||
return global_mgcp_client_conf;
|
||||
}
|
||||
void *global_mgcp_client_ctx = NULL;
|
||||
struct mgcp_client_conf *global_mgcp_client_conf = NULL;
|
||||
|
||||
DEFUN(cfg_mgw_local_ip, cfg_mgw_local_ip_cmd,
|
||||
"mgw local-ip " VTY_IPV46_CMD,
|
||||
"mgw local-ip A.B.C.D",
|
||||
MGW_STR "local bind to connect to MGW from\n"
|
||||
"local bind IPv4 address\n"
|
||||
"local bind IPv6 address\n")
|
||||
"local bind IP address\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
if (!global_mgcp_client_conf)
|
||||
return CMD_ERR_NOTHING_TODO;
|
||||
OSMO_ASSERT(global_mgcp_client_ctx);
|
||||
osmo_talloc_replace_string(global_mgcp_client_ctx,
|
||||
(char **)&conf->local_addr,
|
||||
(char**)&global_mgcp_client_conf->local_addr,
|
||||
argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -78,9 +58,9 @@ DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
|
||||
MGW_STR "local port to connect to MGW from\n"
|
||||
"local bind port\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
conf->local_port = atoi(argv[0]);
|
||||
if (!global_mgcp_client_conf)
|
||||
return CMD_ERR_NOTHING_TODO;
|
||||
global_mgcp_client_conf->local_port = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
|
||||
@@ -89,15 +69,16 @@ ALIAS_DEPRECATED(cfg_mgw_local_port, cfg_mgcpgw_local_port_cmd,
|
||||
"local bind port\n")
|
||||
|
||||
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
|
||||
"mgw remote-ip " VTY_IPV46_CMD,
|
||||
"mgw remote-ip A.B.C.D",
|
||||
MGW_STR "remote IP address to reach the MGW at\n"
|
||||
"remote IPv4 address\n"
|
||||
"remote IPv6 address\n")
|
||||
"remote IP address\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
if (!global_mgcp_client_conf)
|
||||
return CMD_ERR_NOTHING_TODO;
|
||||
OSMO_ASSERT(global_mgcp_client_ctx);
|
||||
osmo_talloc_replace_string(global_mgcp_client_ctx,
|
||||
(char **)&conf->remote_addr, argv[0]);
|
||||
(char**)&global_mgcp_client_conf->remote_addr,
|
||||
argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
|
||||
@@ -110,9 +91,9 @@ DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
|
||||
MGW_STR "remote port to reach the MGW at\n"
|
||||
"remote port\n")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
conf->remote_port = atoi(argv[0]);
|
||||
if (!global_mgcp_client_conf)
|
||||
return CMD_ERR_NOTHING_TODO;
|
||||
global_mgcp_client_conf->remote_port = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
ALIAS_DEPRECATED(cfg_mgw_remote_port, cfg_mgcpgw_remote_port_cmd,
|
||||
@@ -162,396 +143,61 @@ DEFUN(cfg_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")
|
||||
{
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
if (osmo_strlcpy(conf->endpoint_domain_name, argv[0], sizeof(conf->endpoint_domain_name))
|
||||
>= sizeof(conf->endpoint_domain_name)) {
|
||||
vty_out(vty, "%% Error: 'mgw endpoint-domain' name too long, max length is %zu: '%s'%s",
|
||||
sizeof(conf->endpoint_domain_name) - 1, argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
osmo_strlcpy(global_mgcp_client_conf->endpoint_domain_name, argv[0],
|
||||
sizeof(global_mgcp_client_conf->endpoint_domain_name));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_reset_ep_name,
|
||||
cfg_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")
|
||||
{
|
||||
int rc;
|
||||
struct reset_ep *reset_ep;
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
/* stop when the address is already in the list */
|
||||
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
|
||||
if (strcmp(argv[0], reset_ep->name) == 0) {
|
||||
vty_out(vty, "%% duplicate endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
/* the domain name is not part of the actual endpoint name */
|
||||
if (strchr(argv[0], '@')) {
|
||||
vty_out(vty, "%% the endpoint name must be given without domain name ('%s')%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
reset_ep = talloc_zero(global_mgcp_client_ctx, struct reset_ep);
|
||||
OSMO_ASSERT(reset_ep);
|
||||
|
||||
rc = osmo_strlcpy(reset_ep->name, argv[0], sizeof(reset_ep->name));
|
||||
if (rc >= sizeof(reset_ep->name)) {
|
||||
vty_out(vty, "%% Error: 'mgw reset-endpoint' name too long, max length is %zu: '%s'%s",
|
||||
sizeof(reset_ep->name) - 1, argv[0], VTY_NEWLINE);
|
||||
talloc_free(reset_ep);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
llist_add_tail(&reset_ep->list, &conf->reset_epnames);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgw_no_reset_ep_name,
|
||||
cfg_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")
|
||||
{
|
||||
struct reset_ep *reset_ep;
|
||||
struct mgcp_client_conf *conf = get_mgcp_client_config(vty);
|
||||
|
||||
llist_for_each_entry(reset_ep, &conf->reset_epnames, list) {
|
||||
if (strcmp(argv[0], reset_ep->name) == 0) {
|
||||
llist_del(&reset_ep->list);
|
||||
talloc_free(reset_ep);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vty_out(vty, "%% no such endpoint name configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
static int config_write(struct vty *vty, const char *indent, struct mgcp_client_conf *conf)
|
||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
const char *addr;
|
||||
int port;
|
||||
struct reset_ep *reset_ep;
|
||||
|
||||
if (conf->description)
|
||||
vty_out(vty, "%sdescription %s%s", indent, conf->description, VTY_NEWLINE);
|
||||
|
||||
addr = conf->local_addr;
|
||||
addr = global_mgcp_client_conf->local_addr;
|
||||
if (addr)
|
||||
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
|
||||
VTY_NEWLINE);
|
||||
port = conf->local_port;
|
||||
port = global_mgcp_client_conf->local_port;
|
||||
if (port >= 0)
|
||||
vty_out(vty, "%smgw local-port %u%s", indent,
|
||||
(uint16_t)port, VTY_NEWLINE);
|
||||
|
||||
addr = conf->remote_addr;
|
||||
addr = global_mgcp_client_conf->remote_addr;
|
||||
if (addr)
|
||||
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
|
||||
VTY_NEWLINE);
|
||||
port = conf->remote_port;
|
||||
port = global_mgcp_client_conf->remote_port;
|
||||
if (port >= 0)
|
||||
vty_out(vty, "%smgw remote-port %u%s", indent,
|
||||
(uint16_t)port, VTY_NEWLINE);
|
||||
|
||||
if (conf->endpoint_domain_name[0])
|
||||
if (global_mgcp_client_conf->endpoint_domain_name[0])
|
||||
vty_out(vty, "%smgw endpoint-domain %s%s", indent,
|
||||
conf->endpoint_domain_name, VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(reset_ep, &conf->reset_epnames, list)
|
||||
vty_out(vty, "%smgw reset-endpoint %s%s", indent, reset_ep->name, VTY_NEWLINE);
|
||||
global_mgcp_client_conf->endpoint_domain_name, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*! Write out MGCP client config to VTY.
|
||||
* \param[in] vty VTY to which we should print.
|
||||
* \param[in] string used for indentation (e.g. " ").
|
||||
* \returns CMD_SUCCESS on success, CMD_WARNING on error */
|
||||
int mgcp_client_config_write(struct vty *vty, const char *indent)
|
||||
{
|
||||
return config_write(vty, indent, global_mgcp_client_conf);
|
||||
}
|
||||
|
||||
static void vty_init_common(void *talloc_ctx, int node)
|
||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
|
||||
{
|
||||
global_mgcp_client_ctx = talloc_ctx;
|
||||
global_mgcp_client_conf = conf;
|
||||
|
||||
install_lib_element(node, &cfg_mgw_local_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_local_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_remote_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgw_remote_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_endpoint_range_cmd);
|
||||
install_lib_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
|
||||
install_lib_element(node, &cfg_mgw_endpoint_domain_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_reset_ep_name_cmd);
|
||||
install_lib_element(node, &cfg_mgw_no_reset_ep_name_cmd);
|
||||
install_element(node, &cfg_mgw_local_ip_cmd);
|
||||
install_element(node, &cfg_mgw_local_port_cmd);
|
||||
install_element(node, &cfg_mgw_remote_ip_cmd);
|
||||
install_element(node, &cfg_mgw_remote_port_cmd);
|
||||
install_element(node, &cfg_mgw_endpoint_range_cmd);
|
||||
install_element(node, &cfg_mgw_rtp_bts_base_port_cmd);
|
||||
install_element(node, &cfg_mgw_endpoint_domain_name_cmd);
|
||||
|
||||
/* deprecated 'mgcpgw' commands */
|
||||
install_element(node, &cfg_mgcpgw_local_ip_cmd);
|
||||
install_element(node, &cfg_mgcpgw_local_port_cmd);
|
||||
install_element(node, &cfg_mgcpgw_remote_ip_cmd);
|
||||
install_element(node, &cfg_mgcpgw_remote_port_cmd);
|
||||
install_element(node, &cfg_mgcpgw_endpoint_range_cmd);
|
||||
install_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
|
||||
|
||||
osmo_fsm_vty_add_cmds();
|
||||
}
|
||||
|
||||
/*! Set up MGCP client VTY
|
||||
* (called once at startup by the application process).
|
||||
* \param[in] talloc_ctx talloc context to be used by the VTY for allocating memory.
|
||||
* \param[in] node identifier of the node on which the VTY commands should be installed.
|
||||
* \param[in] conf user provided memory to to store the MGCP client configuration data. */
|
||||
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf)
|
||||
{
|
||||
global_mgcp_client_conf = conf;
|
||||
|
||||
/* deprecated 'mgcpgw' commands */
|
||||
install_lib_element(node, &cfg_mgcpgw_local_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgcpgw_local_port_cmd);
|
||||
install_lib_element(node, &cfg_mgcpgw_remote_ip_cmd);
|
||||
install_lib_element(node, &cfg_mgcpgw_remote_port_cmd);
|
||||
install_lib_element(node, &cfg_mgcpgw_endpoint_range_cmd);
|
||||
install_lib_element(node, &cfg_mgcpgw_rtp_bts_base_port_cmd);
|
||||
|
||||
vty_init_common(talloc_ctx, node);
|
||||
}
|
||||
|
||||
static int config_write_pool(struct vty *vty)
|
||||
{
|
||||
struct mgcp_client_pool *pool = global_mgcp_client_pool;
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
unsigned int indent_buf_len = strlen(pool->vty_indent) + 1 + 1;
|
||||
char *indent = talloc_zero_size(vty, indent_buf_len);
|
||||
|
||||
snprintf(indent, indent_buf_len, "%s ", pool->vty_indent);
|
||||
|
||||
llist_for_each_entry(pool_member, &pool->pool, list) {
|
||||
vty_out(vty, "%smgw %u%s", pool->vty_indent, pool_member->nr, VTY_NEWLINE);
|
||||
config_write(vty, indent, &pool_member->conf);
|
||||
}
|
||||
|
||||
talloc_free(indent);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Lookup the selected MGCP client config by its reference number */
|
||||
static struct mgcp_client_pool_member *pool_member_by_nr(unsigned int nr)
|
||||
{
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
struct mgcp_client_pool_member *pool_member_tmp;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return pool_member;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_mgw,
|
||||
cfg_mgw_cmd, "mgw <0-255>", "Select a MGCP client config to setup\n" "reference number\n", CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
if (!pool_member) {
|
||||
pool_member = talloc_zero(global_mgcp_client_pool, struct mgcp_client_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_sub = &pool_member->conf.description;
|
||||
vty->node = global_mgcp_client_pool->vty_node->node;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(cfg_no_mgw,
|
||||
cfg_no_mgw_cmd,
|
||||
"no mgw <0-255>", NO_STR "Select a MGCP client config to remove\n" "reference number\n", CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* Make sure that there are no ongoing calls */
|
||||
if (pool_member->refcount > 0) {
|
||||
vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't remove it now!%s",
|
||||
mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(mgw_reconnect, mgw_reconnect_cmd,
|
||||
"mgw <0-255> reconnect",
|
||||
MGW_STR "reference number\n" "reconfigure and reconnect MGCP client\n", CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* Make sure that there are no ongoing calls */
|
||||
if (pool_member->refcount > 0) {
|
||||
vty_out(vty, "%% MGCP client (MGW %s) is still serving ongoing calls -- can't reconnect it now!%s",
|
||||
mgcp_client_pool_member_name(pool_member), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* 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",
|
||||
mgcp_client_pool_member_name(pool_member), pool_member->conf.remote_addr,
|
||||
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",
|
||||
mgcp_client_pool_member_name(pool_member), argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(mgw_block, mgw_block_cmd,
|
||||
"mgw <0-255> block",
|
||||
MGW_STR "reference number\n" "block MGCP client so that it won't be used for new calls\n", CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
pool_member->blocked = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(mgw_unblock, mgw_unblock_cmd,
|
||||
"mgw <0-255> unblock",
|
||||
MGW_STR "reference number\n" "unblock MGCP client so that it will be available for new calls\n", CMD_ATTR_IMMEDIATE)
|
||||
{
|
||||
int nr = atoi(argv[0]);
|
||||
struct mgcp_client_pool_member *pool_member = NULL;
|
||||
|
||||
pool_member = pool_member_by_nr(nr);
|
||||
if (!pool_member) {
|
||||
vty_out(vty, "%% no such MGCP client configured ('%s')%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
pool_member->blocked = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
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);
|
||||
struct mgcp_client_pool_member *pool_member;
|
||||
|
||||
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);
|
||||
return CMD_SUCCESS;
|
||||
} else if (llist_empty(&global_mgcp_client_pool->pool)) {
|
||||
vty_out(vty, "%% (pool is empty)%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
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, "%% mgcp-client: %s%s", pool_member->client ? "connected" : "disconnected",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, "%% service: %s%s", pool_member->blocked ? "blocked" : "unblocked", VTY_NEWLINE);
|
||||
vty_out(vty, "%% ongoing calls: %u%s", pool_member->refcount, VTY_NEWLINE);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*! Set up MGCP client VTY (pooled)
|
||||
* (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] 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] 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)
|
||||
{
|
||||
/* A pool must be allocated before this function can be called */
|
||||
OSMO_ASSERT(pool);
|
||||
|
||||
/* Never allow this function to be called twice on the same pool */
|
||||
OSMO_ASSERT(!pool->vty_indent);
|
||||
OSMO_ASSERT(!pool->vty_node);
|
||||
|
||||
pool->vty_indent = talloc_strdup(pool, indent);
|
||||
OSMO_ASSERT(pool->vty_indent);
|
||||
pool->vty_node = talloc_zero(pool, struct cmd_node);
|
||||
OSMO_ASSERT(pool->vty_node);
|
||||
pool->vty_node->node = mgw_node;
|
||||
pool->vty_node->vtysh = 1;
|
||||
pool->vty_node->prompt = talloc_strdup(pool->vty_node, "%s(config-mgw)# ");
|
||||
|
||||
install_lib_element(parent_node, &cfg_mgw_cmd);
|
||||
install_lib_element(parent_node, &cfg_no_mgw_cmd);
|
||||
|
||||
install_node(pool->vty_node, config_write_pool);
|
||||
vty_init_common(pool, mgw_node);
|
||||
|
||||
install_element(mgw_node, &cfg_description_cmd);
|
||||
|
||||
install_lib_element(ENABLE_NODE, &mgw_reconnect_cmd);
|
||||
install_lib_element(ENABLE_NODE, &mgw_block_cmd);
|
||||
install_lib_element(ENABLE_NODE, &mgw_unblock_cmd);
|
||||
|
||||
install_lib_element_ve(&mgw_snow_cmd);
|
||||
|
||||
global_mgcp_client_pool = pool;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ AM_CFLAGS = \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOTRAU_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -20,8 +18,6 @@ AM_LDFLAGS = \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -44,8 +40,6 @@ libosmo_mgcp_a_SOURCES = \
|
||||
mgcp_conn.c \
|
||||
mgcp_stat.c \
|
||||
mgcp_endp.c \
|
||||
mgcp_trunk.c \
|
||||
mgcp_ctrl.c \
|
||||
mgcp_ratectr.c \
|
||||
mgcp_e1.c \
|
||||
iuup_protocol.c \
|
||||
iuup_cn_node.c \
|
||||
$(NULL)
|
||||
|
||||
224
src/libosmo-mgcp/iuup_cn_node.c
Normal file
224
src/libosmo-mgcp/iuup_cn_node.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* IuUP Core Network side protocol handling, minimal implementation */
|
||||
|
||||
/*
|
||||
* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr <neels@hofmeyr.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <talloc.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#include <osmocom/netif/rtp.h>
|
||||
|
||||
#include <osmocom/mgcp/iuup_cn_node.h>
|
||||
#include <osmocom/mgcp/iuup_protocol.h>
|
||||
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
|
||||
#define LOG_IUUP_CN(cn, level, fmt, args...) \
|
||||
LOGP(DIUUP, level, "(%s) " fmt, (cn)->name, ## args)
|
||||
|
||||
struct osmo_iuup_cn {
|
||||
struct osmo_iuup_cn_cfg cfg;
|
||||
char *name;
|
||||
uint8_t next_frame_nr;
|
||||
int rtp_payload_type;
|
||||
};
|
||||
|
||||
struct osmo_iuup_cn *osmo_iuup_cn_init(void *ctx, struct osmo_iuup_cn_cfg *cfg,
|
||||
const char *name_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct osmo_iuup_cn *cn = talloc_zero(ctx, struct osmo_iuup_cn);
|
||||
OSMO_ASSERT(cn);
|
||||
|
||||
cn->cfg = *cfg;
|
||||
|
||||
if (!name_fmt)
|
||||
name_fmt = "-";
|
||||
|
||||
va_start(ap, name_fmt);
|
||||
cn->name = talloc_vasprintf(cn, name_fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LOGP(DIUUP, LOGL_INFO, "(%s) Initializing IuUP node\n", cn->name);
|
||||
|
||||
if (!osmo_identifier_valid(cn->name)) {
|
||||
LOGP(DIUUP, LOGL_ERROR, "Attempting to set illegal id for IuUP CN instance: %s\n",
|
||||
osmo_quote_str(cn->name, -1));
|
||||
talloc_free(cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
void osmo_iuup_cn_free(struct osmo_iuup_cn *cn)
|
||||
{
|
||||
talloc_free(cn);
|
||||
}
|
||||
|
||||
static int rx_data(struct osmo_iuup_cn *cn, struct msgb *pdu,
|
||||
struct osmo_iuup_hdr_data *hdr)
|
||||
{
|
||||
/* Remove the IuUP bit from the middle of the buffer by writing the RTP header forward. */
|
||||
/* And append AMR 12.2k header "0xf03c". - AD HOC fix */
|
||||
unsigned int pre_hdr_len = ((uint8_t*)hdr) - pdu->data;
|
||||
memmove(pdu->data + sizeof(*hdr) - 2, pdu->data, pre_hdr_len);
|
||||
((uint8_t*)hdr)[2] = 0xf0;
|
||||
((uint8_t*)hdr)[3] = 0x3c;
|
||||
msgb_pull(pdu, sizeof(*hdr) - 2);
|
||||
|
||||
struct rtp_hdr *h = (struct rtp_hdr*)pdu->data;
|
||||
if (h->payload_type == 96)
|
||||
h->payload_type = 112;
|
||||
|
||||
LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP stripping IuUP header from RTP data\n", cn->name);
|
||||
cn->cfg.rx_payload(pdu, cn->cfg.node_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tx_init_ack(struct osmo_iuup_cn *cn, struct msgb *src_pdu)
|
||||
{
|
||||
/* Send Initialization Ack PDU back to the sender */
|
||||
int rc;
|
||||
struct msgb *ack = msgb_alloc(4096, "IuUP Initialization Ack");
|
||||
OSMO_ASSERT(ack);
|
||||
ack->dst = src_pdu->dst;
|
||||
|
||||
/* Just copy the RTP header that was sent... TODO: tweak some RTP values?? */
|
||||
memcpy(msgb_put(ack, sizeof(struct rtp_hdr)), src_pdu->data, sizeof(struct rtp_hdr));
|
||||
|
||||
osmo_iuup_make_init_ack(ack);
|
||||
|
||||
LOGP(DIUUP, LOGL_DEBUG, "(%s) Sending Initialization ACK %p\n", cn->name, cn->cfg.node_priv);
|
||||
rc = cn->cfg.tx_msg(ack, cn->cfg.node_priv);
|
||||
msgb_free(ack);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rx_control(struct osmo_iuup_cn *cn, struct msgb *pdu,
|
||||
struct osmo_iuup_hdr_ctrl *hdr)
|
||||
{
|
||||
switch (hdr->procedure) {
|
||||
case OSMO_IUUP_PROC_INITIALIZATION:
|
||||
switch (hdr->ack_nack) {
|
||||
case OSMO_IUUP_ACKNACK_PROCEDURE:
|
||||
LOGP(DIUUP, LOGL_INFO, "(%s) Rx IuUP Initialization, sending ACK\n", cn->name);
|
||||
cn->rtp_payload_type = ((struct rtp_hdr*)pdu->data)->payload_type;
|
||||
return tx_init_ack(cn, pdu);
|
||||
|
||||
default:
|
||||
LOGP(DIUUP, LOGL_DEBUG, "(%s) Rx IuUP Initialization, unhandled ack_nack = %d\n",
|
||||
cn->name, hdr->ack_nack);
|
||||
break;
|
||||
}
|
||||
/* Continue to log "unexpected procedure" below. */
|
||||
break;
|
||||
|
||||
case OSMO_IUUP_PROC_ERROR_EVENT:
|
||||
{
|
||||
union osmo_iuup_hdr_ctrl_payload *p = (void*)hdr->payload;
|
||||
LOGP(DIUUP, LOGL_ERROR,
|
||||
"(%s) Rx IuUP Error Event: distance=%u, cause=%u=\"%s\"\n",
|
||||
cn->name, p->error_event.error_distance, p->error_event.error_cause,
|
||||
osmo_iuup_error_cause_name(p->error_event.error_cause));
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LOG_IUUP_CN(cn, LOGL_ERROR,
|
||||
"Rx control PDU with unexpected procedure: 0x%x acknack=0x%x\n",
|
||||
hdr->procedure, hdr->ack_nack);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Feed a received PDU to the IuUP CN node. This function takes ownership of the msgb, it must not be
|
||||
* freed by the caller. */
|
||||
int osmo_iuup_cn_rx_pdu(struct osmo_iuup_cn *cn, struct msgb *pdu)
|
||||
{
|
||||
struct osmo_iuup_hdr_ctrl *is_ctrl;
|
||||
struct osmo_iuup_hdr_data *is_data;
|
||||
int rc;
|
||||
|
||||
rc = osmo_iuup_classify(true, cn->name, pdu, &is_ctrl, &is_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (is_ctrl)
|
||||
return rx_control(cn, pdu, is_ctrl);
|
||||
if (is_data)
|
||||
return rx_data(cn, pdu, is_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static uint8_t next_frame_nr(struct osmo_iuup_cn *cn)
|
||||
{
|
||||
uint8_t frame_nr = cn->next_frame_nr;
|
||||
cn->next_frame_nr = (frame_nr + 1) & 0x0f;
|
||||
return frame_nr;
|
||||
}
|
||||
|
||||
/* Send this RTP packet to the IuUP peer: add IuUP header and call the tx_msg() to transmit the resulting
|
||||
* message to the IuUP peer.
|
||||
* Returns 0 on success, negative on error. */
|
||||
int osmo_iuup_cn_tx_payload(struct osmo_iuup_cn *cn, struct msgb *pdu)
|
||||
{
|
||||
struct rtp_hdr *rtp_was, *rtp;
|
||||
struct osmo_iuup_hdr_data *iuup_hdr;
|
||||
|
||||
/* Splice an IuUP header in between RTP header and payload data */
|
||||
rtp_was = (void*)pdu->data;
|
||||
|
||||
/* copy the RTP header part backwards by the size needed for the IuUP header */
|
||||
/* also strips 2 bytes from the front of RTP payload - AMR header - AD HOC fix */
|
||||
rtp = (void*)msgb_push(pdu, sizeof(*iuup_hdr) - 2);
|
||||
memmove(rtp, rtp_was, sizeof(*rtp));
|
||||
|
||||
/* Send the same payload type to the peer (erm...) */
|
||||
rtp->payload_type = cn->rtp_payload_type;
|
||||
|
||||
iuup_hdr = (void*)rtp->data;
|
||||
|
||||
*iuup_hdr = (struct osmo_iuup_hdr_data){
|
||||
.pdu_type = OSMO_IUUP_PDU_DATA_WITH_CRC,
|
||||
.frame_nr = next_frame_nr(cn),
|
||||
.frame_good = OSMO_IUUP_FRAME_GOOD,
|
||||
};
|
||||
|
||||
osmo_iuup_set_checksums((uint8_t*)iuup_hdr, pdu->tail - (uint8_t*)iuup_hdr);
|
||||
LOGP(DIUUP, LOGL_DEBUG, "(%s) IuUP inserting IuUP header in RTP data (frame nr %u)\n",
|
||||
cn->name, iuup_hdr->frame_nr);
|
||||
|
||||
struct rtp_hdr *h = (struct rtp_hdr*)pdu->data;
|
||||
if (h->payload_type == 112)
|
||||
h->payload_type = 96;
|
||||
|
||||
return cn->cfg.tx_msg(pdu, cn->cfg.node_priv);
|
||||
}
|
||||
286
src/libosmo-mgcp/iuup_protocol.c
Normal file
286
src/libosmo-mgcp/iuup_protocol.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* IuUP Core Network side protocol, minimal implementation */
|
||||
|
||||
/*
|
||||
* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr <neels@hofmeyr.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <osmocom/mgcp/iuup_protocol.h>
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
|
||||
/* Calculating two bytes of CRC is ok to do by a loop */
|
||||
static uint8_t header_crc6(const uint8_t *hdr)
|
||||
{
|
||||
int bit;
|
||||
/* Polynomial: D^6 + D^5 + D^3 + D^2 + D^1 + 1
|
||||
* that's 1101111 or 0x6f;
|
||||
* align its lowest bit with a uint16_t's highest bit: */
|
||||
uint32_t polynomial = 0x6f << 15; // 00110111 10000000 00000000
|
||||
uint32_t remainder = ( ((uint32_t)hdr[0]) << 8 | hdr[1] ) << 6;
|
||||
|
||||
for (bit = 15; bit >= 0; bit--)
|
||||
{
|
||||
if (remainder & (0x40 << bit))
|
||||
remainder ^= polynomial;
|
||||
polynomial >>= 1;
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
/*
|
||||
* Charles Michael Heard's CRC-10 code, from
|
||||
*
|
||||
* http://web.archive.org/web/20061005231950/http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/crc10.html
|
||||
*
|
||||
* with the CRC table initialized with values computed by
|
||||
* his "gen_byte_crc10_table()" routine, rather than by calling that
|
||||
* routine at run time, and with various data type cleanups.
|
||||
*/
|
||||
static const uint16_t byte_crc10_table[256] = {
|
||||
0x0000, 0x0233, 0x0255, 0x0066, 0x0299, 0x00aa, 0x00cc, 0x02ff,
|
||||
0x0301, 0x0132, 0x0154, 0x0367, 0x0198, 0x03ab, 0x03cd, 0x01fe,
|
||||
0x0031, 0x0202, 0x0264, 0x0057, 0x02a8, 0x009b, 0x00fd, 0x02ce,
|
||||
0x0330, 0x0103, 0x0165, 0x0356, 0x01a9, 0x039a, 0x03fc, 0x01cf,
|
||||
0x0062, 0x0251, 0x0237, 0x0004, 0x02fb, 0x00c8, 0x00ae, 0x029d,
|
||||
0x0363, 0x0150, 0x0136, 0x0305, 0x01fa, 0x03c9, 0x03af, 0x019c,
|
||||
0x0053, 0x0260, 0x0206, 0x0035, 0x02ca, 0x00f9, 0x009f, 0x02ac,
|
||||
0x0352, 0x0161, 0x0107, 0x0334, 0x01cb, 0x03f8, 0x039e, 0x01ad,
|
||||
0x00c4, 0x02f7, 0x0291, 0x00a2, 0x025d, 0x006e, 0x0008, 0x023b,
|
||||
0x03c5, 0x01f6, 0x0190, 0x03a3, 0x015c, 0x036f, 0x0309, 0x013a,
|
||||
0x00f5, 0x02c6, 0x02a0, 0x0093, 0x026c, 0x005f, 0x0039, 0x020a,
|
||||
0x03f4, 0x01c7, 0x01a1, 0x0392, 0x016d, 0x035e, 0x0338, 0x010b,
|
||||
0x00a6, 0x0295, 0x02f3, 0x00c0, 0x023f, 0x000c, 0x006a, 0x0259,
|
||||
0x03a7, 0x0194, 0x01f2, 0x03c1, 0x013e, 0x030d, 0x036b, 0x0158,
|
||||
0x0097, 0x02a4, 0x02c2, 0x00f1, 0x020e, 0x003d, 0x005b, 0x0268,
|
||||
0x0396, 0x01a5, 0x01c3, 0x03f0, 0x010f, 0x033c, 0x035a, 0x0169,
|
||||
0x0188, 0x03bb, 0x03dd, 0x01ee, 0x0311, 0x0122, 0x0144, 0x0377,
|
||||
0x0289, 0x00ba, 0x00dc, 0x02ef, 0x0010, 0x0223, 0x0245, 0x0076,
|
||||
0x01b9, 0x038a, 0x03ec, 0x01df, 0x0320, 0x0113, 0x0175, 0x0346,
|
||||
0x02b8, 0x008b, 0x00ed, 0x02de, 0x0021, 0x0212, 0x0274, 0x0047,
|
||||
0x01ea, 0x03d9, 0x03bf, 0x018c, 0x0373, 0x0140, 0x0126, 0x0315,
|
||||
0x02eb, 0x00d8, 0x00be, 0x028d, 0x0072, 0x0241, 0x0227, 0x0014,
|
||||
0x01db, 0x03e8, 0x038e, 0x01bd, 0x0342, 0x0171, 0x0117, 0x0324,
|
||||
0x02da, 0x00e9, 0x008f, 0x02bc, 0x0043, 0x0270, 0x0216, 0x0025,
|
||||
0x014c, 0x037f, 0x0319, 0x012a, 0x03d5, 0x01e6, 0x0180, 0x03b3,
|
||||
0x024d, 0x007e, 0x0018, 0x022b, 0x00d4, 0x02e7, 0x0281, 0x00b2,
|
||||
0x017d, 0x034e, 0x0328, 0x011b, 0x03e4, 0x01d7, 0x01b1, 0x0382,
|
||||
0x027c, 0x004f, 0x0029, 0x021a, 0x00e5, 0x02d6, 0x02b0, 0x0083,
|
||||
0x012e, 0x031d, 0x037b, 0x0148, 0x03b7, 0x0184, 0x01e2, 0x03d1,
|
||||
0x022f, 0x001c, 0x007a, 0x0249, 0x00b6, 0x0285, 0x02e3, 0x00d0,
|
||||
0x011f, 0x032c, 0x034a, 0x0179, 0x0386, 0x01b5, 0x01d3, 0x03e0,
|
||||
0x021e, 0x002d, 0x004b, 0x0278, 0x0087, 0x02b4, 0x02d2, 0x00e1
|
||||
};
|
||||
|
||||
static uint16_t crc10(uint16_t crc10_accum, const uint8_t *payload, unsigned int payload_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < payload_len; i++) {
|
||||
crc10_accum = ((crc10_accum << 8) & 0x300)
|
||||
^ byte_crc10_table[(crc10_accum >> 2) & 0xff]
|
||||
^ payload[i];
|
||||
}
|
||||
return crc10_accum;
|
||||
}
|
||||
|
||||
/* When a payload of a multiple of bytes has run through, we need to still feed 10 bits of zeros into the
|
||||
* CRC10 to get the payload's checksum result that we can send to a peer. That can't be done with above
|
||||
* table, because it acts as if full 16 bits are fed. This stops after 10 bits. */
|
||||
static uint16_t crc10_remainder(uint16_t crc10_accum)
|
||||
{
|
||||
int bit;
|
||||
/* Polynomial: D^10 + D^9 + D^5 + D^4 + D^1 + 1
|
||||
* that's 11000110011 or 0x633;
|
||||
* align its lowest bit with a 10bit value's highest bit: */
|
||||
uint32_t polynomial = 0x633 << 9; // 1100 01100110 00000000
|
||||
uint32_t remainder = ((uint32_t)crc10_accum) << 10;
|
||||
|
||||
/* Run on 10 bits */
|
||||
for (bit = 9; bit >= 0; bit--)
|
||||
{
|
||||
if (remainder & ((1 << 10) << bit))
|
||||
remainder ^= polynomial;
|
||||
polynomial >>= 1;
|
||||
}
|
||||
|
||||
return remainder & 0x3ff;
|
||||
}
|
||||
|
||||
static uint16_t payload_crc10(const uint8_t *payload, unsigned int payload_len)
|
||||
{
|
||||
uint16_t crc10_accum = crc10(0, payload, payload_len);
|
||||
return crc10_remainder(crc10_accum);
|
||||
}
|
||||
|
||||
/* Given an IuUP PDU data block, write the correct header and payload CRC checksums at the right places.
|
||||
*/
|
||||
void osmo_iuup_set_checksums(uint8_t *iuup_header_and_payload, unsigned int header_and_payload_len)
|
||||
{
|
||||
/* For both data and ctrl, the checksums and payload are at the same offset */
|
||||
struct osmo_iuup_hdr_data *hdr = (void*)iuup_header_and_payload;
|
||||
uint16_t crc;
|
||||
unsigned int payload_len;
|
||||
|
||||
hdr->header_crc = header_crc6(iuup_header_and_payload);
|
||||
|
||||
payload_len = iuup_header_and_payload + header_and_payload_len - hdr->payload;
|
||||
crc = payload_crc10(hdr->payload, payload_len);
|
||||
hdr->payload_crc_hi = (crc >> 8) & 0x3;
|
||||
hdr->payload_crc_lo = crc & 0xff;
|
||||
|
||||
}
|
||||
|
||||
/* Validate minimum message sizes, IuUP PDU type, header- and payload checksums. If it is a Control
|
||||
* Procedure PDU, return the header position in is_ctrl, if it is a Data PDU, return the header position
|
||||
* in is_data. If log_errors is true, log on DIUUP with the given log label for context. Return NULL in
|
||||
* both is_ctrl and is_data, and return a negative error code if the PDU could not be identified as a
|
||||
* valid RTP PDU containing an IuUP part. */
|
||||
int osmo_iuup_classify(bool log_errors,
|
||||
const char *log_label,
|
||||
struct msgb *pdu,
|
||||
struct osmo_iuup_hdr_ctrl **is_ctrl,
|
||||
struct osmo_iuup_hdr_data **is_data)
|
||||
{
|
||||
struct rtp_hdr *rtp = (void*)pdu->data;
|
||||
struct osmo_iuup_hdr_ctrl *hdr = (void*)rtp->data;
|
||||
unsigned int payload_len;
|
||||
uint16_t crc_calculated;
|
||||
uint16_t crc_from_peer;
|
||||
|
||||
#define ERR(fmt, args...) do { \
|
||||
if (log_errors) \
|
||||
LOGP(DIUUP, LOGL_ERROR, "(%s) " fmt, log_label? : "-", ## args); \
|
||||
return -EINVAL; \
|
||||
} while (0)
|
||||
|
||||
if (is_ctrl)
|
||||
*is_ctrl = NULL;
|
||||
if (is_data)
|
||||
*is_data = NULL;
|
||||
|
||||
/* We need at least a header of 4 bytes. The osmo_iuup_hdr_ctrl already includes a byte of
|
||||
* payload, so use osmo_iuup_hdr_data to check the minimum here. */
|
||||
if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_data)))
|
||||
ERR("IuUP PDU too short: %u\n", pdu->len);
|
||||
|
||||
/* Let's not validate checksums if the header type isn't sane */
|
||||
switch (hdr->pdu_type) {
|
||||
case OSMO_IUUP_PDU_DATA_WITH_CRC:
|
||||
/* If the caller isn't interested in data PDUs, cut short here. */
|
||||
if (!is_data)
|
||||
return 0;
|
||||
break;
|
||||
case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
|
||||
/* If the caller isn't interested in control PDUs, cut short here. */
|
||||
if (!is_ctrl)
|
||||
return 0;
|
||||
if (pdu->len < (sizeof(*rtp) + sizeof(struct osmo_iuup_hdr_ctrl)))
|
||||
ERR("IuUP control PDU too short: %u\n", pdu->len);
|
||||
break;
|
||||
default:
|
||||
ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
|
||||
}
|
||||
|
||||
/* For both data and ctrl, the checksums and payload are at the same offset */
|
||||
|
||||
crc_calculated = header_crc6((uint8_t*)hdr);
|
||||
if (crc_calculated != hdr->header_crc)
|
||||
ERR("IuUP PDU with invalid header CRC (peer sent 0x%x, calculated 0x%x)\n",
|
||||
hdr->header_crc, crc_calculated);
|
||||
|
||||
payload_len = pdu->tail - hdr->payload;
|
||||
crc_calculated = payload_crc10(hdr->payload, payload_len);
|
||||
crc_from_peer = (((uint16_t)hdr->payload_crc_hi) << 8) | hdr->payload_crc_lo;
|
||||
if (crc_from_peer != crc_calculated)
|
||||
ERR("IuUP PDU with invalid payload CRC (peer sent 0x%x, calculated 0x%x)\n",
|
||||
crc_from_peer, crc_calculated);
|
||||
|
||||
switch (hdr->pdu_type) {
|
||||
case OSMO_IUUP_PDU_DATA_WITH_CRC:
|
||||
if (is_data)
|
||||
*is_data = (void*)hdr;
|
||||
return 0;
|
||||
case OSMO_IUUP_PDU_CONTROL_PROCEDURE:
|
||||
if (is_ctrl)
|
||||
*is_ctrl = hdr;
|
||||
return 0;
|
||||
default:
|
||||
ERR("IuUP with invalid type: %u\n", hdr->pdu_type);
|
||||
}
|
||||
#undef ERR
|
||||
}
|
||||
|
||||
/* Return true if this RTP packet contains an IuUP Initialization header (detect IuUP peer). */
|
||||
bool osmo_iuup_is_init(struct msgb *pdu)
|
||||
{
|
||||
struct osmo_iuup_hdr_ctrl *is_ctrl;
|
||||
osmo_iuup_classify(false, NULL, pdu, &is_ctrl, NULL);
|
||||
return is_ctrl
|
||||
&& is_ctrl->procedure == OSMO_IUUP_PROC_INITIALIZATION
|
||||
&& is_ctrl->ack_nack == OSMO_IUUP_ACKNACK_PROCEDURE;
|
||||
}
|
||||
|
||||
/* Append an IuUP Initialization ACK message */
|
||||
void osmo_iuup_make_init_ack(struct msgb *ack)
|
||||
{
|
||||
/* Send Initialization Ack PDU back to the sender */
|
||||
struct osmo_iuup_hdr_ctrl *hdr;
|
||||
OSMO_ASSERT(ack);
|
||||
|
||||
hdr = (void*)msgb_put(ack, sizeof(*hdr));
|
||||
|
||||
*hdr = (struct osmo_iuup_hdr_ctrl){
|
||||
.pdu_type = OSMO_IUUP_PDU_CONTROL_PROCEDURE,
|
||||
.ack_nack = OSMO_IUUP_ACKNACK_ACK,
|
||||
.procedure = OSMO_IUUP_PROC_INITIALIZATION,
|
||||
};
|
||||
|
||||
osmo_iuup_set_checksums((uint8_t*)hdr, sizeof(*hdr));
|
||||
}
|
||||
|
||||
const struct value_string osmo_iuup_error_cause_names[] = {
|
||||
{ 0, "CRC error of frame header" },
|
||||
{ 1, "CRC error of frame payload" },
|
||||
{ 2, "Unexpected frame number" },
|
||||
{ 3, "Frame loss" },
|
||||
{ 4, "PDU type unknown" },
|
||||
{ 5, "Unknown procedure" },
|
||||
{ 6, "Unknown reserved value" },
|
||||
{ 7, "Unknown field" },
|
||||
{ 8, "Frame too short" },
|
||||
{ 9, "Missing fields" },
|
||||
{ 16, "Unexpected PDU type" },
|
||||
{ 17, "spare" },
|
||||
{ 18, "Unexpected procedure" },
|
||||
{ 19, "Unexpected RFCI" },
|
||||
{ 20, "Unexpected value" },
|
||||
{ 42, "Initialisation failure" },
|
||||
{ 43, "Initialisation failure (network error, timer expiry)" },
|
||||
{ 44, "Initialisation failure (Iu UP function error, repeated NACK)" },
|
||||
{ 45, "Rate control failure" },
|
||||
{ 46, "Error event failure" },
|
||||
{ 47, "Time Alignment not supported" },
|
||||
{ 48, "Requested Time Alignment not possible" },
|
||||
{ 49, "Iu UP Mode version not supported" },
|
||||
{}
|
||||
};
|
||||
@@ -17,13 +17,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_codec.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Helper function to dump codec information of a specified codec to a printable
|
||||
@@ -61,8 +56,8 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
|
||||
endp = conn->conn->endp;
|
||||
|
||||
if (rtp->codecs_assigned == 0) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n",
|
||||
mgcp_conn_dump(conn->conn));
|
||||
LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x conn:%s no codecs available\n", ENDPOINT_NUMBER(endp),
|
||||
mgcp_conn_dump(conn->conn));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,8 +65,8 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
|
||||
for (i = 0; i < rtp->codecs_assigned; i++) {
|
||||
codec = &rtp->codecs[i];
|
||||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s",
|
||||
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x conn:%s codecs[%u]:%s", ENDPOINT_NUMBER(endp),
|
||||
mgcp_conn_dump(conn->conn), i, dump_codec(codec));
|
||||
|
||||
if (codec == rtp->codec)
|
||||
LOGPC(DLMGCP, LOGL_DEBUG, " [selected]");
|
||||
@@ -81,57 +76,36 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn)
|
||||
}
|
||||
|
||||
/* Initalize or reset codec information with default data. */
|
||||
static void codec_init(struct mgcp_rtp_codec *codec)
|
||||
void codec_init(struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
*codec = (struct mgcp_rtp_codec){
|
||||
.payload_type = -1,
|
||||
.frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM,
|
||||
.frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN,
|
||||
.rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE,
|
||||
.channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS,
|
||||
.subtype_name = "",
|
||||
.audio_name = "",
|
||||
};
|
||||
}
|
||||
|
||||
static void codec_free(struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
*codec = (struct mgcp_rtp_codec){};
|
||||
if (codec->subtype_name)
|
||||
talloc_free(codec->subtype_name);
|
||||
if (codec->audio_name)
|
||||
talloc_free(codec->audio_name);
|
||||
memset(codec, 0, sizeof(*codec));
|
||||
codec->payload_type = -1;
|
||||
codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
|
||||
codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
|
||||
codec->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
|
||||
codec->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
|
||||
}
|
||||
|
||||
/*! Initalize or reset codec information with default data.
|
||||
* \param[out] conn related rtp-connection. */
|
||||
void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < conn->end.codecs_assigned; i++)
|
||||
codec_free(&conn->end.codecs[i]);
|
||||
memset(conn->end.codecs, 0, sizeof(conn->end.codecs));
|
||||
conn->end.codecs_assigned = 0;
|
||||
conn->end.codec = NULL;
|
||||
}
|
||||
|
||||
/*! Add codec configuration depending on payload type and/or codec name. This
|
||||
* function uses the input parameters to extrapolate the full codec information.
|
||||
* \param[out] codec configuration (caller provided memory).
|
||||
* \param[out] conn related rtp-connection.
|
||||
* \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
|
||||
* \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1").
|
||||
* \param[in] param optional codec parameters (set to NULL when unused).
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param)
|
||||
/* Set members of struct mgcp_rtp_codec, extrapolate in missing information */
|
||||
static int codec_set(void *ctx, struct mgcp_rtp_codec *codec,
|
||||
int payload_type, const char *audio_name, unsigned int pt_offset)
|
||||
{
|
||||
int rate;
|
||||
int channels;
|
||||
struct mgcp_rtp_codec *codec;
|
||||
unsigned int pt_offset = conn->end.codecs_assigned;
|
||||
|
||||
/* The amount of codecs we can store is limited, make sure we do not
|
||||
* overrun this limit. */
|
||||
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
|
||||
return -EINVAL;
|
||||
|
||||
/* First unused entry */
|
||||
codec = &conn->end.codecs[conn->end.codecs_assigned];
|
||||
char audio_codec[64];
|
||||
|
||||
/* Initalize the codec struct with some default data to begin with */
|
||||
codec_init(codec);
|
||||
@@ -139,13 +113,12 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
|
||||
if (payload_type != PTYPE_UNDEFINED) {
|
||||
/* Make sure we do not get any reserved or undefined type numbers */
|
||||
/* See also: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */
|
||||
if ((payload_type == 1 || payload_type == 2 || payload_type == 19)
|
||||
|| (payload_type >= 72 && payload_type <= 76)
|
||||
|| (payload_type >= 127)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot add codec, payload type number %d is reserved\n",
|
||||
payload_type);
|
||||
if (payload_type == 1 || payload_type == 2 || payload_type == 19)
|
||||
goto error;
|
||||
if (payload_type >= 72 && payload_type <= 76)
|
||||
goto error;
|
||||
if (payload_type >= 127)
|
||||
goto error;
|
||||
}
|
||||
|
||||
codec->payload_type = payload_type;
|
||||
}
|
||||
@@ -156,55 +129,46 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
|
||||
if (!audio_name) {
|
||||
switch (payload_type) {
|
||||
case 0:
|
||||
strcpy(codec->audio_name, "PCMU/8000/1");
|
||||
audio_name = talloc_strdup(ctx, "PCMU/8000/1");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(codec->audio_name, "GSM/8000/1");
|
||||
audio_name = talloc_strdup(ctx, "GSM/8000/1");
|
||||
break;
|
||||
case 8:
|
||||
strcpy(codec->audio_name, "PCMA/8000/1");
|
||||
audio_name = talloc_strdup(ctx, "PCMA/8000/1");
|
||||
break;
|
||||
case 18:
|
||||
strcpy(codec->audio_name, "G729/8000/1");
|
||||
audio_name = talloc_strdup(ctx, "G729/8000/1");
|
||||
break;
|
||||
default:
|
||||
/* The given payload type is not known to us, or it
|
||||
* it is a dynamic payload type for which we do not
|
||||
* know the audio name. We must give up here */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "No audio codec name given, and payload type %d unknown\n",
|
||||
payload_type);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
OSMO_STRLCPY_ARRAY(codec->audio_name, audio_name);
|
||||
}
|
||||
|
||||
/* Now we extract the codec subtype name, rate and channels. The latter
|
||||
* two are optional. If they are not present we use the safe defaults
|
||||
* above. */
|
||||
if (strlen(codec->audio_name) >= sizeof(codec->subtype_name)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Audio codec too long: %s\n", osmo_quote_str(codec->audio_name, -1));
|
||||
if (strlen(audio_name) > sizeof(audio_codec))
|
||||
goto error;
|
||||
}
|
||||
channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS;
|
||||
rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE;
|
||||
if (sscanf(codec->audio_name, "%63[^/]/%d/%d", codec->subtype_name, &rate, &channels) < 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Invalid audio codec: %s\n", osmo_quote_str(codec->audio_name, -1));
|
||||
if (sscanf(audio_name, "%63[^/]/%d/%d", audio_codec, &rate, &channels) < 1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Note: We only accept configurations with one audio channel! */
|
||||
if (channels != 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot handle audio codec with more than one channel: %s\n",
|
||||
osmo_quote_str(codec->audio_name, -1));
|
||||
if (channels != 1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
codec->rate = rate;
|
||||
codec->channels = channels;
|
||||
codec->subtype_name = talloc_strdup(ctx, audio_codec);
|
||||
codec->audio_name = talloc_strdup(ctx, audio_name);
|
||||
codec->payload_type = payload_type;
|
||||
|
||||
if (!strcmp(codec->subtype_name, "G729")) {
|
||||
if (!strcmp(audio_codec, "G729")) {
|
||||
codec->frame_duration_num = 10;
|
||||
codec->frame_duration_den = 1000;
|
||||
} else {
|
||||
@@ -214,7 +178,6 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
|
||||
|
||||
/* Derive the payload type if it is unknown */
|
||||
if (codec->payload_type == PTYPE_UNDEFINED) {
|
||||
/* TODO: This is semi dead code, see OS#4150 */
|
||||
|
||||
/* For the known codecs from the static range we restore
|
||||
* the IANA or 3GPP assigned payload type number */
|
||||
@@ -250,46 +213,80 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud
|
||||
* 110 onwards 3gpp defines prefered codec types, which are
|
||||
* also fixed, see above) */
|
||||
if (codec->payload_type < 0) {
|
||||
/* FIXME: pt_offset is completely unrelated and useless here, any of those numbers may already
|
||||
* have been added to the codecs. Instead, there should be an iterator checking for an actually
|
||||
* unused dynamic payload type number. */
|
||||
codec->payload_type = 96 + pt_offset;
|
||||
if (codec->payload_type > 109) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Ran out of payload type numbers to assign dynamically\n");
|
||||
if (codec->payload_type > 109)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy over optional codec parameters */
|
||||
if (param) {
|
||||
codec->param = *param;
|
||||
codec->param_present = true;
|
||||
} else
|
||||
codec->param_present = false;
|
||||
|
||||
conn->end.codecs_assigned++;
|
||||
return 0;
|
||||
error:
|
||||
/* Make sure we leave a clean codec entry on error. */
|
||||
codec_free(codec);
|
||||
codec_init(codec);
|
||||
memset(codec, 0, sizeof(*codec));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*! Add codec configuration depending on payload type and/or codec name. This
|
||||
* function uses the input parameters to extrapolate the full codec information.
|
||||
* \param[out] codec configuration (caller provided memory).
|
||||
* \param[out] conn related rtp-connection.
|
||||
* \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined).
|
||||
* \param[in] audio_name audio codec name (e.g. "GSM/8000/1").
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* The amount of codecs we can store is limited, make sure we do not
|
||||
* overrun this limit. */
|
||||
if (conn->end.codecs_assigned >= MGCP_MAX_CODECS)
|
||||
return -EINVAL;
|
||||
|
||||
rc = codec_set(conn->conn, &conn->end.codecs[conn->end.codecs_assigned], payload_type, audio_name,
|
||||
conn->end.codecs_assigned);
|
||||
if (rc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
conn->end.codecs_assigned++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the given codec is applicable on the specified endpoint
|
||||
* Helper function for mgcp_codec_decide() */
|
||||
static bool is_codec_compatible(const struct mgcp_endpoint *endp, const struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
char codec_name[64];
|
||||
|
||||
/* A codec name must be set, if not, this might mean that the codec
|
||||
* (payload type) that was assigned is unknown to us so we must stop
|
||||
* here. */
|
||||
if (!strlen(codec->subtype_name))
|
||||
if (!codec->subtype_name)
|
||||
return false;
|
||||
|
||||
/* FIXME: implement meaningful checks to make sure that the given codec
|
||||
* is compatible with the given endpoint */
|
||||
/* We now extract the codec_name (letters before the /, e.g. "GSM"
|
||||
* from the audio name that is stored in the trunk configuration.
|
||||
* We do not compare to the full audio_name because we expect that
|
||||
* "GSM", "GSM/8000" and "GSM/8000/1" are all compatible when the
|
||||
* audio name of the codec is set to "GSM" */
|
||||
if (sscanf(endp->tcfg->audio_name, "%63[^/]/%*d/%*d", codec_name) < 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
/* Finally we check if the subtype_name we have generated from the
|
||||
* audio_name in the trunc struct patches the codec_name of the
|
||||
* given codec */
|
||||
if (strcasecmp(codec_name, codec->subtype_name) == 0)
|
||||
return true;
|
||||
|
||||
/* FIXME: It is questinable that the method to pick a compatible
|
||||
* codec can work properly. Since this useses tcfg->audio_name, as
|
||||
* a reference, which is set to "AMR/8000" permanently.
|
||||
* tcfg->audio_name must be updated by the first connection that
|
||||
* has been made on an endpoint, so that the second connection
|
||||
* can make a meaningful decision here */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Decide for one suitable codec
|
||||
@@ -316,7 +313,7 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
|
||||
for (i = 0; i < rtp->codecs_assigned; i++) {
|
||||
/* When no transcoding is available, avoid codecs that would
|
||||
* require transcoding. */
|
||||
if (endp->trunk->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
|
||||
if (endp->tcfg->no_audio_transcoding && !is_codec_compatible(endp, &rtp->codecs[i])) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "transcoding not available, skipping codec: %d/%s\n",
|
||||
rtp->codecs[i].payload_type, rtp->codecs[i].subtype_name);
|
||||
continue;
|
||||
@@ -345,28 +342,9 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode.
|
||||
* See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB
|
||||
* Media Type Registration":
|
||||
*
|
||||
* octet-align: Permissible values are 0 and 1. If 1, octet-aligned
|
||||
* operation SHALL be used. If 0 or if not present,
|
||||
* bandwidth-efficient operation is employed.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4867
|
||||
*/
|
||||
static bool amr_is_octet_aligned(const struct mgcp_rtp_codec *codec)
|
||||
{
|
||||
if (!codec->param_present)
|
||||
return false;
|
||||
if (!codec->param.amr_octet_aligned_present)
|
||||
return false;
|
||||
return codec->param.amr_octet_aligned;
|
||||
}
|
||||
|
||||
/* Compare two codecs, all parameters must match up, except for the payload type
|
||||
* number. */
|
||||
static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
|
||||
static bool codecs_cmp(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b)
|
||||
{
|
||||
if (codec_a->rate != codec_b->rate)
|
||||
return false;
|
||||
@@ -376,12 +354,10 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c
|
||||
return false;
|
||||
if (codec_a->frame_duration_den != codec_b->frame_duration_den)
|
||||
return false;
|
||||
if (strcmp(codec_a->audio_name, codec_b->audio_name))
|
||||
return false;
|
||||
if (strcmp(codec_a->subtype_name, codec_b->subtype_name))
|
||||
return false;
|
||||
if (!strcmp(codec_a->subtype_name, "AMR")) {
|
||||
if (amr_is_octet_aligned(codec_a) != amr_is_octet_aligned(codec_b))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -422,7 +398,7 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
|
||||
codecs_assigned = rtp_dst->codecs_assigned;
|
||||
OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS);
|
||||
for (i = 0; i < codecs_assigned; i++) {
|
||||
if (codecs_same(codec_src, &rtp_dst->codecs[i])) {
|
||||
if (codecs_cmp(codec_src, &rtp_dst->codecs[i])) {
|
||||
codec_dst = &rtp_dst->codecs[i];
|
||||
break;
|
||||
}
|
||||
@@ -432,28 +408,3 @@ int mgcp_codec_pt_translate(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp
|
||||
|
||||
return codec_dst->payload_type;
|
||||
}
|
||||
|
||||
/* Find the payload type number configured for a specific codec by SDP.
|
||||
* For example, IuUP gets assigned a payload type number, and the endpoint needs to translate that to the number
|
||||
* assigned to "AMR" on the other conn (by a=rtpmap:N).
|
||||
* \param conn The side of an endpoint to get the payload type number for (to translate the payload type number to).
|
||||
* \param subtype_name SDP codec name without parameters (e.g. "AMR").
|
||||
* \param match_nr Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times
|
||||
* with incrementing match_nr.
|
||||
* \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found.
|
||||
*/
|
||||
const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn,
|
||||
const char *subtype_name, unsigned int match_nr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < conn->end.codecs_assigned; i++) {
|
||||
if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) {
|
||||
if (match_nr) {
|
||||
match_nr--;
|
||||
continue;
|
||||
}
|
||||
return &conn->end.codecs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -21,18 +21,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_network.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp_common.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_sdp.h>
|
||||
#include <osmocom/mgcp/mgcp_codec.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <ctype.h>
|
||||
|
||||
const static struct rate_ctr_group_desc rate_ctr_group_desc = {
|
||||
@@ -78,23 +74,23 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
|
||||
}
|
||||
}
|
||||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR, "unable to generate a unique connectionIdentifier\n");
|
||||
LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x, unable to generate a unique connectionIdentifier\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize rtp connection struct with default values */
|
||||
static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
|
||||
static void mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
|
||||
{
|
||||
struct mgcp_rtp_end *end = &conn_rtp->end;
|
||||
/* FIXME: Each new rate counter group requires an unique index. At the
|
||||
* moment we generate this index using this counter, but perhaps there
|
||||
* is a more concious way to assign the indexes. */
|
||||
static atomic_uint rate_ctr_index = 0;
|
||||
static unsigned int rate_ctr_index = 0;
|
||||
|
||||
conn_rtp->type = MGCP_RTP_DEFAULT;
|
||||
conn_rtp->osmux.cid_allocated = false;
|
||||
conn_rtp->osmux.cid = 0;
|
||||
conn_rtp->osmux.allocated_cid = -1;
|
||||
|
||||
/* backpointer to the generic part of the connection */
|
||||
conn->u.rtp.conn = conn;
|
||||
@@ -111,44 +107,22 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *
|
||||
end->output_enabled = 0;
|
||||
end->maximum_packet_time = -1;
|
||||
|
||||
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
|
||||
if (!conn_rtp->rate_ctr_group)
|
||||
return -1;
|
||||
|
||||
conn_rtp->state.in_stream.err_ts_ctr = 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->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
|
||||
conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index);
|
||||
conn_rtp->state.in_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[IN_STREAM_ERR_TSTMP_CTR];
|
||||
conn_rtp->state.out_stream.err_ts_ctr = &conn_rtp->rate_ctr_group->ctr[OUT_STREAM_ERR_TSTMP_CTR];
|
||||
rate_ctr_index++;
|
||||
|
||||
/* Make sure codec table is reset */
|
||||
mgcp_codec_reset_all(conn_rtp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup rtp connection struct */
|
||||
static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp)
|
||||
{
|
||||
if (mgcp_conn_rtp_is_osmux(conn_rtp))
|
||||
conn_osmux_disable(conn_rtp);
|
||||
osmux_disable_conn(conn_rtp);
|
||||
osmux_release_cid(conn_rtp);
|
||||
mgcp_free_rtp_port(&conn_rtp->end);
|
||||
rate_ctr_group_free(conn_rtp->rate_ctr_group);
|
||||
mgcp_codec_reset_all(conn_rtp);
|
||||
}
|
||||
|
||||
void mgcp_conn_watchdog_cb(void *data)
|
||||
{
|
||||
struct mgcp_conn *conn = data;
|
||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n");
|
||||
mgcp_conn_free(conn->endp, conn->id);
|
||||
}
|
||||
|
||||
void mgcp_conn_watchdog_kick(struct mgcp_conn *conn)
|
||||
{
|
||||
int timeout = conn->endp->trunk->cfg->conn_timeout;
|
||||
if (!timeout)
|
||||
return;
|
||||
|
||||
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "watchdog kicked\n");
|
||||
osmo_timer_schedule(&conn->watchdog, timeout, 0);
|
||||
}
|
||||
|
||||
/*! allocate a new connection list entry.
|
||||
@@ -184,10 +158,7 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
||||
|
||||
switch (type) {
|
||||
case MGCP_CONN_TYPE_RTP:
|
||||
if (mgcp_rtp_conn_init(&conn->u.rtp, conn) < 0) {
|
||||
talloc_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
mgcp_rtp_conn_init(&conn->u.rtp, conn);
|
||||
break;
|
||||
default:
|
||||
/* NOTE: This should never be called with an
|
||||
@@ -196,10 +167,7 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
/* Initialize watchdog */
|
||||
osmo_timer_setup(&conn->watchdog, mgcp_conn_watchdog_cb, conn);
|
||||
mgcp_conn_watchdog_kick(conn);
|
||||
mgcp_endp_add_conn(endp, conn);
|
||||
llist_add(&conn->entry, &endp->conns);
|
||||
|
||||
return conn;
|
||||
}
|
||||
@@ -256,10 +224,12 @@ struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
|
||||
static void
|
||||
aggregate_rtp_conn_stats(struct mgcp_trunk_config *trunk, 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 = trunk->all_rtp_conn_stats;
|
||||
struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
|
||||
int i;
|
||||
|
||||
if (all_stats == NULL || conn_stats == NULL)
|
||||
return;
|
||||
@@ -269,13 +239,10 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con
|
||||
* All other counters in both counter groups correspond to each other. */
|
||||
OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
|
||||
|
||||
/* all other counters are [now] updated in real-time */
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(all_stats, IN_STREAM_ERR_TSTMP_CTR),
|
||||
rate_ctr_group_get_ctr(conn_stats, IN_STREAM_ERR_TSTMP_CTR)->current);
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(all_stats, OUT_STREAM_ERR_TSTMP_CTR),
|
||||
rate_ctr_group_get_ctr(conn_stats, OUT_STREAM_ERR_TSTMP_CTR)->current);
|
||||
for (i = 0; i < conn_stats->desc->num_ctr; i++)
|
||||
rate_ctr_add(&all_stats->ctr[i], conn_stats->ctr[i].current);
|
||||
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
|
||||
rate_ctr_inc(&all_stats->ctr[RTP_NUM_CONNECTIONS]);
|
||||
}
|
||||
|
||||
/*! free a connection by its ID.
|
||||
@@ -289,9 +256,15 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
/* Run endpoint cleanup action. By this we inform the endpoint about
|
||||
* the removal of the connection and allow it to clean up its inner
|
||||
* state accordingly */
|
||||
if (endp->type->cleanup_cb)
|
||||
endp->type->cleanup_cb(endp, conn);
|
||||
|
||||
switch (conn->type) {
|
||||
case MGCP_CONN_TYPE_RTP:
|
||||
aggregate_rtp_conn_stats(endp, &conn->u.rtp);
|
||||
aggregate_rtp_conn_stats(endp->tcfg, &conn->u.rtp);
|
||||
mgcp_rtp_conn_cleanup(&conn->u.rtp);
|
||||
break;
|
||||
default:
|
||||
@@ -301,9 +274,7 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
osmo_timer_del(&conn->watchdog);
|
||||
mgcp_endp_remove_conn(endp, conn);
|
||||
/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */
|
||||
llist_del(&conn->entry);
|
||||
talloc_free(conn);
|
||||
}
|
||||
|
||||
@@ -328,10 +299,12 @@ void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
|
||||
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
|
||||
{
|
||||
struct mgcp_conn *conn;
|
||||
struct mgcp_conn *conn_tmp;
|
||||
|
||||
/* Drop all items in the list, might be consecutive! */
|
||||
while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry)))
|
||||
/* Drop all items in the list */
|
||||
llist_for_each_entry_safe(conn, conn_tmp, &endp->conns, entry) {
|
||||
mgcp_conn_free(endp, conn->id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -342,7 +315,6 @@ void mgcp_conn_free_all(struct mgcp_endpoint *endp)
|
||||
char *mgcp_conn_dump(struct mgcp_conn *conn)
|
||||
{
|
||||
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!conn) {
|
||||
snprintf(str, sizeof(str), "(null connection)");
|
||||
@@ -356,7 +328,7 @@ char *mgcp_conn_dump(struct mgcp_conn *conn)
|
||||
"rtp:%u rtcp:%u)",
|
||||
conn->name,
|
||||
conn->id,
|
||||
osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf),
|
||||
inet_ntoa(conn->u.rtp.end.addr),
|
||||
ntohs(conn->u.rtp.end.rtp_port),
|
||||
ntohs(conn->u.rtp.end.rtcp_port));
|
||||
break;
|
||||
@@ -392,13 +364,3 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! get oldest connection in the list.
|
||||
* \param[in] endp associated endpoint */
|
||||
struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (llist_empty(&endp->conns))
|
||||
return NULL;
|
||||
|
||||
return llist_last_entry(&endp->conns, struct mgcp_conn, entry);
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* (C) 2020 by Harald Welte <laforge@gnumonks.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
|
||||
|
||||
static int mgw_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
||||
void **node_data, int *i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct ctrl_handle *mgw_ctrl_interface_setup(struct mgcp_config *cfg,
|
||||
const char *bind_addr, uint16_t port)
|
||||
{
|
||||
return ctrl_interface_setup_dynip2(cfg, bind_addr, port, mgw_ctrl_node_lookup,
|
||||
_LAST_CTRL_NODE);
|
||||
}
|
||||
@@ -1,689 +0,0 @@
|
||||
/* E1 traffic handling */
|
||||
|
||||
/*
|
||||
* (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Philipp Maier
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/abis/abis.h>
|
||||
|
||||
#include <osmocom/trau/trau_sync.h>
|
||||
#include <osmocom/trau/trau_frame.h>
|
||||
#include <osmocom/trau/trau_rtp.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
#include <osmocom/mgcp/mgcp_e1.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
#define DEBUG_BITS_MAX 80
|
||||
#define DEBUG_BYTES_MAX 40
|
||||
#define DEBUG_E1_TS 0
|
||||
#define E1_TS_BYTES 160
|
||||
#define E1_TRAU_BITS 320
|
||||
#define E1_TRAU_BITS_MSGB 2048
|
||||
|
||||
static struct mgcp_config *cfg;
|
||||
|
||||
static const struct e1inp_line_ops dummy_e1_line_ops = {
|
||||
.sign_link_up = NULL,
|
||||
.sign_link_down = NULL,
|
||||
.sign_link = NULL,
|
||||
};
|
||||
|
||||
/* EFR idle frame */
|
||||
static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/* FR idle frame */
|
||||
static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/* Idle speech frame, see also GSM 08.60, chapter 3.4 */
|
||||
static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
/* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may
|
||||
* run empty. In order to make sure that the TRAU frame transmission continues
|
||||
* we generate idle TRAU frames here. */
|
||||
static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_data)
|
||||
{
|
||||
struct mgcp_endpoint *endp = user_data;
|
||||
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
||||
struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
|
||||
uint8_t *ptr;
|
||||
const uint8_t *ptr_ft;
|
||||
enum osmo_trau_frame_type ft;
|
||||
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
|
||||
|
||||
/* Choose an appropiate idle frame type */
|
||||
ft = endp->e1.trau_rtp_st->type;
|
||||
switch (ft) {
|
||||
case OSMO_TRAU16_FT_FR:
|
||||
ptr_ft = idle_tf_fr;
|
||||
break;
|
||||
case OSMO_TRAU16_FT_EFR:
|
||||
ptr_ft = idle_tf_efr;
|
||||
break;
|
||||
default:
|
||||
/* FIXME: What about 8k subslots and AMR frames? */
|
||||
ptr_ft = idle_tf_spch;
|
||||
}
|
||||
|
||||
/* Put the replacement into a message buffer and enqueue it into the
|
||||
* I.460 multiplexer */
|
||||
ptr = msgb_put(msg, E1_TRAU_BITS);
|
||||
memcpy(ptr, ptr_ft, E1_TRAU_BITS);
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-IDLE-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg),
|
||||
osmo_ubit_dump(msgb_data(msg), msgb_length(msg) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg)));
|
||||
osmo_i460_mux_enqueue(endp->e1.schan, msg);
|
||||
}
|
||||
|
||||
/* called by I.460 de-multeiplexer; feed output of I.460 demux into TRAU frame sync */
|
||||
static void e1_i460_demux_bits_cb(struct osmo_i460_subchan *schan, void *user_data, const ubit_t *bits,
|
||||
unsigned int num_bits)
|
||||
{
|
||||
struct mgcp_endpoint *endp = user_data;
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u bits from subslot: %s...\n", num_bits,
|
||||
osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));
|
||||
|
||||
OSMO_ASSERT(endp->e1.trau_sync_fi);
|
||||
osmo_trau_sync_rx_ubits(endp->e1.trau_sync_fi, bits, num_bits);
|
||||
}
|
||||
|
||||
/* called for each synchronized TRAU frame received; decode frame + convert to RTP
|
||||
* (the resulting frame will be prepended with an all-zero (12-byte) rtp header) */
|
||||
static void sync_frame_out_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)
|
||||
{
|
||||
unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
|
||||
struct mgcp_endpoint *endp = user_data;
|
||||
struct msgb *msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx-from-E1");
|
||||
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
||||
struct mgcp_conn *conn_dst;
|
||||
struct osmo_trau_frame fr;
|
||||
int rc;
|
||||
|
||||
if (!bits || num_bits == 0)
|
||||
goto skip;
|
||||
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: receiving %u TRAU frame bits from E1 subslot: %s...\n",
|
||||
num_bits, osmo_ubit_dump(bits, num_bits > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : num_bits));
|
||||
|
||||
/* Decode TRAU frame */
|
||||
switch (endp->e1.scd.rate) {
|
||||
case OSMO_I460_RATE_8k:
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 8k trau frame...\n");
|
||||
rc = osmo_trau_frame_decode_8k(&fr, bits, OSMO_TRAU_DIR_UL);
|
||||
break;
|
||||
case OSMO_I460_RATE_16k:
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoding 16k trau frame...\n");
|
||||
rc = osmo_trau_frame_decode_16k(&fr, bits, OSMO_TRAU_DIR_UL);
|
||||
break;
|
||||
default:
|
||||
/* TRAU frames only exist in 8K or 16K subslots. */
|
||||
OSMO_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to decode trau frame\n");
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* Check if the payload type is supported and what the expected lenth
|
||||
* of the RTP payload will be. */
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: decoded trau frame type: %s\n",
|
||||
osmo_trau_frame_type_name(fr.type));
|
||||
|
||||
/* Convert decoded trau frame to RTP frame */
|
||||
struct osmo_trau2rtp_state t2rs = {
|
||||
.type = fr.type,
|
||||
};
|
||||
rc = osmo_trau2rtp(msgb_data(msg) + rtp_hdr_len, msg->data_len - rtp_hdr_len, &fr, &t2rs);
|
||||
if (rc <= 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: unable to convert trau frame to RTP audio\n");
|
||||
goto skip;
|
||||
}
|
||||
msgb_put(msg, rtp_hdr_len + rc);
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-RX: encoded %u bytes of RTP audio: %s\n", rc,
|
||||
osmo_hexdump(msgb_data(msg) + rtp_hdr_len, msgb_length(msg) - rtp_hdr_len));
|
||||
|
||||
/* Forward RTP data to IP */
|
||||
conn_dst = llist_first_entry(&endp->conns, struct mgcp_conn, entry);
|
||||
if (!conn_dst) {
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG,
|
||||
"E1-I.460-RX: unable to forward RTP audio data from E1: no connection to forward an incoming RTP packet to\n");
|
||||
goto skip;
|
||||
}
|
||||
OSMO_ASSERT(conn_dst->type == MGCP_CONN_TYPE_RTP);
|
||||
|
||||
mgcp_send(endp, 1, NULL, msg, &conn_dst->u.rtp, &conn_dst->u.rtp);
|
||||
|
||||
msgb_free(msg);
|
||||
return;
|
||||
skip:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
|
||||
msgb_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Function to handle outgoing E1 traffic */
|
||||
static void e1_send(struct e1inp_ts *ts, struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_c(trunk, E1_TS_BYTES, "E1-TX-timeslot-bytes");
|
||||
uint8_t *ptr;
|
||||
|
||||
/* Get E1 frame from I.460 multiplexer */
|
||||
ptr = msgb_put(msg, E1_TS_BYTES);
|
||||
osmo_i460_mux_out(&trunk->e1.i460_ts[ts->num - 1], ptr, E1_TS_BYTES);
|
||||
|
||||
#if DEBUG_E1_TS == 1
|
||||
LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-TX: (ts:%u) sending %u bytes: %s...\n", ts->num, msgb_length(msg),
|
||||
osmo_hexdump_nospc(msgb_data(msg),
|
||||
msgb_length(msg) > DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
|
||||
#endif
|
||||
/* Hand data over to the E1 stack */
|
||||
msgb_enqueue(&ts->raw.tx_queue, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Callback function to handle incoming E1 traffic */
|
||||
static void e1_recv_cb(struct e1inp_ts *ts, struct msgb *msg)
|
||||
{
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
/* Find associated trunk */
|
||||
trunk = mgcp_trunk_by_line_num(cfg, ts->line->num);
|
||||
if (!trunk) {
|
||||
LOGP(DE1, LOGL_ERROR, "E1-RX: unable to find a trunk for E1-line %u!\n", ts->line->num);
|
||||
msgb_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the incoming data looks sane */
|
||||
if (msgb_length(msg) != E1_TS_BYTES) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_NOTICE,
|
||||
"E1-RX: (ts:%u) expected length is %u, actual length is %u!\n", ts->num, E1_TS_BYTES,
|
||||
msgb_length(msg));
|
||||
}
|
||||
#if DEBUG_E1_TS == 1
|
||||
LOGPTRUNK(trunk, DE1, LOGL_DEBUG, "E1-RX: (ts:%u) receiving %u bytes: %s...\n", ts->num,
|
||||
msgb_length(msg), osmo_hexdump_nospc(msgb_data(msg),
|
||||
msgb_length(msg) >
|
||||
DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
|
||||
#endif
|
||||
|
||||
/* Hand data over to the I.460 demultiplexer. */
|
||||
osmo_i460_demux_in(&trunk->e1.i460_ts[ts->num - 1], msgb_data(msg), msgb_length(msg));
|
||||
|
||||
/* Trigger sending of pending E1 traffic */
|
||||
e1_send(ts, trunk);
|
||||
|
||||
/* e1inp_rx_ts() does not free() msgb */
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static int e1_init(struct mgcp_trunk *trunk, uint8_t ts_nr)
|
||||
{
|
||||
/*! Each timeslot needs only to be configured once. The Timeslot then
|
||||
* stays open and permanently receives data. It is then up to the
|
||||
* I.460 demultiplexer to add/remove subchannels as needed. It is
|
||||
* allowed to call this function multiple times since we check if the
|
||||
* timeslot is already configured. */
|
||||
|
||||
struct e1inp_line *e1_line;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(ts_nr > 0 || ts_nr < NUM_E1_TS);
|
||||
cfg = trunk->cfg;
|
||||
|
||||
if (trunk->e1.ts_in_use[ts_nr - 1]) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u already set up, skipping...\n", ts_nr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get E1 line */
|
||||
e1_line = e1inp_line_find(trunk->e1.vty_line_nr);
|
||||
if (!e1_line) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "no such E1 line %u - check VTY config!\n",
|
||||
trunk->e1.vty_line_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
e1inp_line_bind_ops(e1_line, &dummy_e1_line_ops);
|
||||
|
||||
/* Configure E1 timeslot */
|
||||
rc = e1inp_ts_config_raw(&e1_line->ts[ts_nr - 1], e1_line, e1_recv_cb);
|
||||
if (rc < 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to put E1 timeslot %u in raw mode.\n", ts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = e1inp_line_update(e1_line);
|
||||
if (rc < 0) {
|
||||
LOGPTRUNK(trunk, DE1, LOGL_ERROR, "failed to update E1 timeslot %u.\n", ts_nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGPTRUNK(trunk, DE1, LOGL_INFO, "E1 timeslot %u set up successfully.\n", ts_nr);
|
||||
trunk->e1.ts_in_use[ts_nr - 1] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine a suitable TRAU frame type for a given codec */
|
||||
static enum osmo_trau_frame_type determine_trau_fr_type(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,
|
||||
uint8_t amr_ft, struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
||||
return OSMO_TRAU16_FT_FR;
|
||||
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
||||
return OSMO_TRAU16_FT_EFR;
|
||||
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
|
||||
return OSMO_TRAU16_FT_HR;
|
||||
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
|
||||
if (i460_rate == OSMO_I460_RATE_8k) {
|
||||
switch (amr_ft) {
|
||||
case AMR_4_75:
|
||||
case AMR_5_15:
|
||||
case AMR_5_90:
|
||||
return OSMO_TRAU8_AMR_LOW;
|
||||
case AMR_6_70:
|
||||
return OSMO_TRAU8_AMR_6k7;
|
||||
case AMR_7_40:
|
||||
return OSMO_TRAU8_AMR_7k4;
|
||||
default:
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
||||
"E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);
|
||||
return OSMO_TRAU_FT_NONE;
|
||||
}
|
||||
}
|
||||
return OSMO_TRAU16_FT_AMR;
|
||||
} else {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
|
||||
sdp_subtype_name);
|
||||
return OSMO_TRAU_FT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine a suitable TRAU frame type for a given codec */
|
||||
static enum osmo_tray_sync_pat_id determine_trau_sync_pat(char *sdp_subtype_name, enum osmo_i460_rate i460_rate,
|
||||
uint8_t amr_ft, struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (strcmp(sdp_subtype_name, "GSM") == 0)
|
||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
else if (strcmp(sdp_subtype_name, "GSM-EFR") == 0)
|
||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
else if (strcmp(sdp_subtype_name, "GSM-HR-08") == 0)
|
||||
return OSMO_TRAU_SYNCP_8_HR;
|
||||
else if (strcmp(sdp_subtype_name, "AMR") == 0) {
|
||||
if (i460_rate == OSMO_I460_RATE_8k) {
|
||||
switch (amr_ft) {
|
||||
case AMR_4_75:
|
||||
case AMR_5_15:
|
||||
case AMR_5_90:
|
||||
return OSMO_TRAU_SYNCP_8_AMR_LOW;
|
||||
case AMR_6_70:
|
||||
return OSMO_TRAU_SYNCP_8_AMR_6K7;
|
||||
case AMR_7_40:
|
||||
return OSMO_TRAU_SYNCP_8_AMR_7K4;
|
||||
default:
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
||||
"E1-TRAU-TX: unsupported or illegal AMR frame type: %u\n", amr_ft);
|
||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
}
|
||||
}
|
||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
} else {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR, "E1-TRAU-TX: unsupported or illegal codec subtype name: %s\n",
|
||||
sdp_subtype_name);
|
||||
return OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find out if a given TRAU frame type is AMR */
|
||||
static bool tf_type_is_amr(enum osmo_trau_frame_type ft)
|
||||
{
|
||||
|
||||
switch (ft) {
|
||||
case OSMO_TRAU16_FT_AMR:
|
||||
case OSMO_TRAU8_AMR_LOW:
|
||||
case OSMO_TRAU8_AMR_6k7:
|
||||
case OSMO_TRAU8_AMR_7k4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* !Equip E1 endpoint with I.460 mux resources.
|
||||
* \param[in] endp endpoint to equip
|
||||
* \param[in] ts E1 timeslot number.
|
||||
* \param[in] ss E1 subslot number.
|
||||
* \param[in] offset E1 bit offset.
|
||||
* \returns 0 on success, -EINVAL on error. */
|
||||
int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8_t offs)
|
||||
{
|
||||
int rc;
|
||||
enum osmo_tray_sync_pat_id sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
|
||||
OSMO_ASSERT(ts != 0);
|
||||
OSMO_ASSERT(ts != 0xFF);
|
||||
OSMO_ASSERT(ss != 0xFF);
|
||||
OSMO_ASSERT(offs != 0xFF);
|
||||
|
||||
memset(&endp->e1, 0, sizeof(endp->e1));
|
||||
|
||||
endp->e1.last_amr_ft = AMR_4_75;
|
||||
|
||||
/* Set up E1 line / timeslot */
|
||||
rc = e1_init(endp->trunk, ts);
|
||||
if (rc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Set up I.460 mux */
|
||||
switch (e1_rates[ss]) {
|
||||
case 64:
|
||||
endp->e1.scd.rate = OSMO_I460_RATE_64k;
|
||||
endp->e1.scd.demux.num_bits = 160 * 8;
|
||||
break;
|
||||
case 32:
|
||||
endp->e1.scd.rate = OSMO_I460_RATE_32k;
|
||||
endp->e1.scd.demux.num_bits = 80 * 8;
|
||||
break;
|
||||
case 16:
|
||||
endp->e1.scd.rate = OSMO_I460_RATE_16k;
|
||||
endp->e1.scd.demux.num_bits = 40 * 8;
|
||||
sync_pat_id = OSMO_TRAU_SYNCP_16_FR_EFR;
|
||||
break;
|
||||
case 8:
|
||||
endp->e1.scd.rate = OSMO_I460_RATE_8k;
|
||||
endp->e1.scd.demux.num_bits = 20 * 8;
|
||||
sync_pat_id = OSMO_TRAU_SYNCP_8_HR;
|
||||
break;
|
||||
}
|
||||
endp->e1.scd.bit_offset = offs;
|
||||
endp->e1.scd.demux.out_cb_bits = e1_i460_demux_bits_cb;
|
||||
endp->e1.scd.demux.out_cb_bytes = NULL;
|
||||
endp->e1.scd.demux.user_data = endp;
|
||||
endp->e1.scd.mux.in_cb_queue_empty = e1_i460_mux_empty_cb;
|
||||
endp->e1.scd.mux.user_data = endp;
|
||||
|
||||
LOGPENDP(endp, DE1, LOGL_INFO, "adding I.460 subchannel: ts=%u, bit_offset=%u, rate=%uk, num_bits=%lu\n", ts,
|
||||
offs, e1_rates[ss], endp->e1.scd.demux.num_bits);
|
||||
endp->e1.schan = osmo_i460_subchan_add(endp, &endp->trunk->e1.i460_ts[ts - 1], &endp->e1.scd);
|
||||
if (!endp->e1.schan) {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 subchannel: failed!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (endp->e1.scd.rate == OSMO_I460_RATE_16k || endp->e1.scd.rate == OSMO_I460_RATE_8k) {
|
||||
/* TRAU frames are only specified for 16k and 8k subslots. For all other subslot
|
||||
* types the concept of TRAU frames does not apply. However, at the moment this
|
||||
* is the only format we currently support in osmo-mgw */
|
||||
endp->e1.trau_sync_fi = osmo_trau_sync_alloc(endp, "trau-sync", sync_frame_out_cb, sync_pat_id, endp);
|
||||
if (!endp->e1.trau_sync_fi) {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR, "adding I.460 TRAU frame sync: failed!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
endp->e1.trau_rtp_st = talloc_zero(endp->e1.trau_sync_fi, struct osmo_trau2rtp_state);
|
||||
endp->e1.trau_rtp_st->type = OSMO_TRAU_FT_NONE;
|
||||
} else {
|
||||
LOGPENDP(endp, DE1, LOGL_ERROR,
|
||||
"osmo-mgw currently only supports 16K and 8K subslots (TRAU frames)!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Update E1 related parameters (codec and sync pattern).
|
||||
* \param[in] endp endpoint to update. */
|
||||
void mgcp_e1_endp_update(struct mgcp_endpoint *endp)
|
||||
{
|
||||
struct mgcp_conn *conn;
|
||||
struct mgcp_rtp_codec *codec;
|
||||
enum osmo_tray_sync_pat_id sync_pat_id;
|
||||
|
||||
/* In order to determine the codec, find the oldest connection on
|
||||
* the endpoint and use its codec information. Normally on an E1
|
||||
* endpoint no more than one connection should exist. */
|
||||
conn = mgcp_conn_get_oldest(endp);
|
||||
OSMO_ASSERT(conn);
|
||||
codec = conn->u.rtp.end.codec;
|
||||
OSMO_ASSERT(codec);
|
||||
|
||||
/* Update codec information */
|
||||
endp->e1.trau_rtp_st->type =
|
||||
determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
||||
endp->e1.last_codec = codec;
|
||||
|
||||
/* Update sync pattern */
|
||||
sync_pat_id = determine_trau_sync_pat(codec->subtype_name, endp->e1.scd.rate, endp->e1.last_amr_ft, endp);
|
||||
osmo_trau_sync_set_pat(endp->e1.trau_sync_fi, sync_pat_id);
|
||||
}
|
||||
|
||||
/*! Remove E1 resources from endpoint
|
||||
* \param[in] endp endpoint to release. */
|
||||
void mgcp_e1_endp_release(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "removing I.460 subchannel and sync...\n");
|
||||
|
||||
if (endp->e1.schan)
|
||||
osmo_i460_subchan_del(endp->e1.schan);
|
||||
if (endp->e1.trau_rtp_st)
|
||||
talloc_free(endp->e1.trau_rtp_st);
|
||||
if (endp->e1.trau_sync_fi)
|
||||
osmo_fsm_inst_term(endp->e1.trau_sync_fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
|
||||
memset(&endp->e1, 0, sizeof(endp->e1));
|
||||
}
|
||||
|
||||
/*! Accept RTP message buffer with RTP data and enqueue voice data for E1 transmit.
|
||||
* \param[in] endp related endpoint (does not take ownership).
|
||||
* \param[in] codec configuration.
|
||||
* \param[in] msg RTP message buffer (including RTP header).
|
||||
* \returns 0 on success, -1 on ERROR. */
|
||||
int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
|
||||
{
|
||||
struct msgb *msg_tf = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
|
||||
struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
|
||||
unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
|
||||
struct osmo_trau_frame tf;
|
||||
uint8_t amr_ft;
|
||||
int rc;
|
||||
|
||||
/* Extract AMR frame type from AMR head (if AMR is used) */
|
||||
if (tf_type_is_amr(endp->e1.trau_rtp_st->type))
|
||||
amr_ft = (msgb_data(msg)[rtp_hdr_len + 1] >> 3) & 0xf;
|
||||
else
|
||||
amr_ft = 0xff;
|
||||
|
||||
/* Adapt TRAU frame type on codec changes */
|
||||
OSMO_ASSERT(endp->e1.last_codec);
|
||||
if (codec != endp->e1.last_codec || (amr_ft != 0xff && amr_ft != endp->e1.last_amr_ft)) {
|
||||
endp->e1.trau_rtp_st->type =
|
||||
determine_trau_fr_type(codec->subtype_name, endp->e1.scd.rate, amr_ft, endp);
|
||||
endp->e1.last_codec = codec;
|
||||
endp->e1.last_amr_ft = amr_ft;
|
||||
}
|
||||
if (endp->e1.trau_rtp_st->type == OSMO_TRAU_FT_NONE)
|
||||
goto skip;
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: using trau frame type for encoding: %s\n",
|
||||
osmo_trau_frame_type_name(endp->e1.trau_rtp_st->type));
|
||||
|
||||
/* Convert from RTP to TRAU format */
|
||||
msg->l2h = msgb_data(msg) + rtp_hdr_len;
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: decoding %u bytes of RTP audio to TRAU format: %s\n",
|
||||
msgb_length(msg), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
|
||||
memset(&tf, 0, sizeof(tf));
|
||||
tf.dir = OSMO_TRAU_DIR_DL;
|
||||
rc = osmo_rtp2trau(&tf, msgb_l2(msg), msgb_l2len(msg), endp->e1.trau_rtp_st);
|
||||
if (rc < 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG,
|
||||
"E1-I.460-TX: failed to decode from RTP payload format to TRAU format\n");
|
||||
goto skip;
|
||||
}
|
||||
rc = osmo_trau_frame_encode(msgb_data(msg_tf), msg_tf->data_len, &tf);
|
||||
if (rc < 0) {
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: failed to encode TRAU frame\n");
|
||||
goto skip;
|
||||
}
|
||||
msgb_put(msg_tf, rc);
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: enquing %u trau frame bits: %s...\n", msgb_length(msg_tf),
|
||||
osmo_ubit_dump(msgb_data(msg_tf),
|
||||
msgb_length(msg_tf) > DEBUG_BITS_MAX ? DEBUG_BITS_MAX : msgb_length(msg_tf)));
|
||||
|
||||
/* Enqueue data to I.460 multiplexer */
|
||||
OSMO_ASSERT(endp->e1.schan);
|
||||
OSMO_ASSERT(endp->e1.trau_sync_fi);
|
||||
|
||||
osmo_i460_mux_enqueue(endp->e1.schan, msg_tf);
|
||||
LOGPENDP(endp, DE1, LOGL_DEBUG, "E1-I.460-TX: %u bits of audio enqued for E1 tx\n", msgb_length(msg_tf));
|
||||
|
||||
return 0;
|
||||
skip:
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
|
||||
msgb_free(msg_tf);
|
||||
return -1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Endpoint types */
|
||||
|
||||
/*
|
||||
* (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Philipp Maier
|
||||
@@ -21,100 +21,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/mgcp/mgcp_e1.h>
|
||||
#include <osmocom/core/stat_item.h>
|
||||
|
||||
#define E1_RATE_MAX 64
|
||||
#define E1_OFFS_MAX 8
|
||||
|
||||
/* Endpoint typeset definition */
|
||||
const struct mgcp_endpoint_typeset ep_typeset = {
|
||||
/* Specify endpoint properties for RTP endpoint */
|
||||
.rtp = {
|
||||
.max_conns = 2,
|
||||
.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
|
||||
.cleanup_cb = mgcp_cleanup_rtp_bridge_cb,
|
||||
},
|
||||
/* Specify endpoint properties for E1 endpoint */
|
||||
.e1 = {
|
||||
.max_conns = 1,
|
||||
.dispatch_rtp_cb = mgcp_dispatch_e1_bridge_cb,
|
||||
.cleanup_cb = mgcp_cleanup_e1_bridge_cb,
|
||||
},
|
||||
.rtp.max_conns = 2,
|
||||
.rtp.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb,
|
||||
.rtp.cleanup_cb = mgcp_cleanup_rtp_bridge_cb
|
||||
};
|
||||
|
||||
/* Generate virtual endpoint name from given parameters */
|
||||
static char *gen_virtual_epname(void *ctx, const char *domain,
|
||||
unsigned int index)
|
||||
{
|
||||
return talloc_asprintf(ctx, "%s%x@%s",
|
||||
MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, index, domain);
|
||||
}
|
||||
|
||||
/* Generate E1 endpoint name from given numeric parameters */
|
||||
static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr,
|
||||
uint8_t ts_nr, uint8_t ss_nr)
|
||||
{
|
||||
unsigned int rate;
|
||||
unsigned int offset;
|
||||
|
||||
OSMO_ASSERT(ss_nr < sizeof(e1_rates));
|
||||
|
||||
rate = e1_rates[ss_nr];
|
||||
offset = e1_offsets[ss_nr];
|
||||
|
||||
return talloc_asprintf(ctx, "%s%u/s-%u/su%u-%u@%s",
|
||||
MGCP_ENDPOINT_PREFIX_E1_TRUNK, trunk_nr, ts_nr,
|
||||
rate, offset, domain);
|
||||
}
|
||||
|
||||
/*! allocate an endpoint and set default values.
|
||||
* \param[in] trunk configuration.
|
||||
* \param[in] name endpoint index.
|
||||
* \returns endpoint on success, NULL on failure. */
|
||||
struct mgcp_endpoint *mgcp_endp_alloc(struct mgcp_trunk *trunk,
|
||||
unsigned int index)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
endp = talloc_zero(trunk->endpoints, struct mgcp_endpoint);
|
||||
if (!endp)
|
||||
return NULL;
|
||||
|
||||
INIT_LLIST_HEAD(&endp->conns);
|
||||
endp->trunk = trunk;
|
||||
|
||||
switch (trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
endp->type = &ep_typeset.rtp;
|
||||
endp->name = gen_virtual_epname(endp, trunk->cfg->domain, index);
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
endp->type = &ep_typeset.e1;
|
||||
endp->name = gen_e1_epname(endp, trunk->cfg->domain,
|
||||
trunk->trunk_nr,
|
||||
index / MGCP_ENDP_E1_SUBSLOTS, index % MGCP_ENDP_E1_SUBSLOTS);
|
||||
break;
|
||||
default:
|
||||
osmo_panic("Cannot allocate unimplemented trunk type %d! %s:%d\n",
|
||||
trunk->trunk_type, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
return endp;
|
||||
}
|
||||
|
||||
/*! release endpoint, all open connections are closed.
|
||||
* \param[in] endp endpoint to release */
|
||||
void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "Releasing endpoint\n");
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Releasing endpoint:0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
|
||||
/* Normally this function should only be called when
|
||||
* all connections have been removed already. In case
|
||||
@@ -122,12 +45,6 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
* RSIP is executed), free them all at once. */
|
||||
mgcp_conn_free_all(endp);
|
||||
|
||||
/* We must only decrement the stat item when the endpoint as actually
|
||||
* claimed. An endpoint is claimed when a call-id is set */
|
||||
if (endp->callid)
|
||||
osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
|
||||
TRUNK_STAT_ENDPOINTS_USED), 1);
|
||||
|
||||
/* Reset endpoint parameters and states */
|
||||
talloc_free(endp->callid);
|
||||
endp->callid = NULL;
|
||||
@@ -135,543 +52,5 @@ void mgcp_endp_release(struct mgcp_endpoint *endp)
|
||||
endp->local_options.string = NULL;
|
||||
talloc_free(endp->local_options.codec);
|
||||
endp->local_options.codec = NULL;
|
||||
|
||||
if (endp->trunk->trunk_type == MGCP_TRUNK_E1)
|
||||
mgcp_e1_endp_release(endp);
|
||||
}
|
||||
|
||||
/* Check if the endpoint name contains the prefix (e.g. "rtpbridge/" or
|
||||
* "ds/e1-") and write the epname without the prefix back to the memory
|
||||
* pointed at by epname. (per trunk the prefix is the same for all endpoints,
|
||||
* so no ambiguity is introduced) */
|
||||
static void chop_epname_prefix(char *epname, const struct mgcp_trunk *trunk)
|
||||
{
|
||||
size_t prefix_len;
|
||||
switch (trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
|
||||
if (strncmp
|
||||
(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
|
||||
prefix_len) == 0)
|
||||
memmove(epname, epname + prefix_len,
|
||||
strlen(epname) - prefix_len + 1);
|
||||
return;
|
||||
case MGCP_TRUNK_E1:
|
||||
prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
|
||||
if (strncmp
|
||||
(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
|
||||
prefix_len) == 0)
|
||||
memmove(epname, epname + prefix_len,
|
||||
strlen(epname) - prefix_len + 1);
|
||||
return;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the endpoint name contains a suffix (e.g. "@mgw") and truncate
|
||||
* epname by writing a '\0' char where the suffix starts. */
|
||||
static void chop_epname_suffix(char *epname, const struct mgcp_trunk *trunk)
|
||||
{
|
||||
char *suffix_begin;
|
||||
|
||||
/* Endpoints on the virtual trunk may have a domain name that is
|
||||
* followed after an @ character, this can be chopped off. All
|
||||
* other supported trunk types do not have any suffixes that may
|
||||
* be chopped off */
|
||||
if (trunk->trunk_type == MGCP_TRUNK_VIRTUAL) {
|
||||
suffix_begin = strchr(epname, '@');
|
||||
if (!suffix_begin)
|
||||
return;
|
||||
*suffix_begin = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Convert all characters in epname to lowercase and strip trunk prefix and
|
||||
* endpoint name suffix (domain name) from epname. The result is written to
|
||||
* to the memory pointed at by epname_stripped. The expected size of the
|
||||
* result is either equal or lower then the length of the input string
|
||||
* (epname)
|
||||
* \param[out] epname_stripped pointer to store the stripped ep name.
|
||||
* \param[in] epname endpoint name to lookup.
|
||||
* \param[in] trunk where the endpoint is located. */
|
||||
void mgcp_endp_strip_name(char *epname_stripped, const char *epname,
|
||||
const struct mgcp_trunk *trunk)
|
||||
{
|
||||
osmo_str_tolower_buf(epname_stripped, MGCP_ENDPOINT_MAXLEN, epname);
|
||||
chop_epname_prefix(epname_stripped, trunk);
|
||||
chop_epname_suffix(epname_stripped, trunk);
|
||||
}
|
||||
|
||||
/* Go through the trunk and find a random free (no active calls) endpoint,
|
||||
* this function is called when a wildcarded request is carried out, which
|
||||
* means that it is up to the MGW to choose a random free endpoint. */
|
||||
static struct mgcp_endpoint *find_free_endpoint(const struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < trunk->number_endpoints; i++) {
|
||||
endp = trunk->endpoints[i];
|
||||
/* A free endpoint must not serve a call already and it must
|
||||
* be available. */
|
||||
if (endp->callid == NULL && mgcp_endp_avail(endp))
|
||||
return endp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Find an endpoint of a trunk specified by its name.
|
||||
* \param[in] epname endpoint name to check.
|
||||
* \param[in] trunk mgcp_trunk that might have this endpoint.
|
||||
* \returns NULL if no ep found, else endpoint. */
|
||||
struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname,
|
||||
const struct mgcp_trunk *trunk)
|
||||
{
|
||||
char epname_stripped[MGCP_ENDPOINT_MAXLEN];
|
||||
char epname_stripped_endp[MGCP_ENDPOINT_MAXLEN];
|
||||
struct mgcp_endpoint *endp;
|
||||
unsigned int i;
|
||||
|
||||
/* Strip irrelevant information from the endpoint name */
|
||||
mgcp_endp_strip_name(epname_stripped, epname, trunk);
|
||||
|
||||
for (i = 0; i < trunk->number_endpoints; i++) {
|
||||
endp = trunk->endpoints[i];
|
||||
mgcp_endp_strip_name(epname_stripped_endp, endp->name, trunk);
|
||||
if (strcmp(epname_stripped_endp, epname_stripped) == 0)
|
||||
return endp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Check if the given epname refers to a wildcarded request or to a specific
|
||||
* endpoint.
|
||||
* \param[in] epname endpoint name to check
|
||||
* \returns true if epname refers to wildcarded request, else false. */
|
||||
bool mgcp_endp_is_wildcarded(const char *epname)
|
||||
{
|
||||
if (strstr(epname, "*"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Find an endpoint by its name on a specified trunk.
|
||||
* \param[out] cause pointer to store cause code, can be NULL.
|
||||
* \param[in] epname endpoint name to lookup.
|
||||
* \param[in] trunk where the endpoint is located.
|
||||
* \returns endpoint or NULL if endpoint was not found. */
|
||||
struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname,
|
||||
const struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
if (cause)
|
||||
*cause = 0;
|
||||
|
||||
/* At the moment we only support a primitive ('*'-only) method of
|
||||
* wildcarded endpoint searches that picks the next free endpoint on
|
||||
* a trunk. */
|
||||
if (mgcp_endp_is_wildcarded(epname)) {
|
||||
endp = find_free_endpoint(trunk);
|
||||
if (endp) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
|
||||
"(trunk:%d) found free endpoint: %s\n",
|
||||
trunk->trunk_nr, endp->name);
|
||||
return endp;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"(trunk:%d) Not able to find a free endpoint\n",
|
||||
trunk->trunk_nr);
|
||||
if (cause)
|
||||
*cause = -403;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find an endpoint by its name (if wildcarded request is not
|
||||
* applicable) */
|
||||
endp = mgcp_endp_find_specific(epname, trunk);
|
||||
if (endp) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_DEBUG,
|
||||
"(trunk:%d) found endpoint: %s\n",
|
||||
trunk->trunk_nr, endp->name);
|
||||
return endp;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"(trunk:%d) Not able to find specified endpoint: %s\n",
|
||||
trunk->trunk_nr, epname);
|
||||
if (cause)
|
||||
*cause = -500;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Find an endpoint by its name, search at all trunks.
|
||||
* \param[out] cause, pointer to store cause code, can be NULL.
|
||||
* \param[in] epname, must contain trunk prefix.
|
||||
* \param[in] cfg, mgcp configuration (trunks).
|
||||
* \returns endpoint or NULL if endpoint was not found. */
|
||||
struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname,
|
||||
struct mgcp_config *cfg)
|
||||
{
|
||||
struct mgcp_trunk *trunk;
|
||||
struct mgcp_endpoint *endp;
|
||||
char epname_lc[MGCP_ENDPOINT_MAXLEN];
|
||||
|
||||
osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
|
||||
epname = epname_lc;
|
||||
|
||||
if (cause)
|
||||
*cause = -500;
|
||||
|
||||
/* Identify the trunk where the endpoint is located */
|
||||
trunk = mgcp_trunk_by_name(cfg, epname);
|
||||
if (!trunk)
|
||||
return NULL;
|
||||
|
||||
/* Identify the endpoint on the trunk */
|
||||
endp = mgcp_endp_by_name_trunk(cause, epname, trunk);
|
||||
if (!endp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cause)
|
||||
*cause = 0;
|
||||
return endp;
|
||||
}
|
||||
|
||||
/* Get the E1 timeslot number from a given E1 endpoint name
|
||||
* (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
|
||||
static uint8_t e1_ts_nr_from_epname(const char *epname)
|
||||
{
|
||||
char buf[MGCP_ENDPOINT_MAXLEN + 1];
|
||||
char *save_ptr = NULL;
|
||||
char *buf_ptr = buf;
|
||||
char *token;
|
||||
unsigned long int res = 0;
|
||||
|
||||
strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
|
||||
|
||||
while (1) {
|
||||
token = strtok_r(buf_ptr, "/", &save_ptr);
|
||||
buf_ptr = NULL;
|
||||
if (!token)
|
||||
break;
|
||||
if (strncmp(token, "s-", 2) == 0) {
|
||||
errno = 0;
|
||||
res = strtoul(token + 2, NULL, 10);
|
||||
if (errno == ERANGE || res > NUM_E1_TS)
|
||||
return 0xff;
|
||||
return (uint8_t) res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* Get the E1 timeslot number from a given E1 endpoint name
|
||||
* (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
|
||||
static uint8_t e1_rate_from_epname(const char *epname)
|
||||
{
|
||||
char buf[MGCP_ENDPOINT_MAXLEN + 1];
|
||||
char *save_ptr = NULL;
|
||||
char *buf_ptr = buf;
|
||||
char *token;
|
||||
unsigned long int res = 0;
|
||||
unsigned int i;
|
||||
|
||||
strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
|
||||
|
||||
while (1) {
|
||||
token = strtok_r(buf_ptr, "/", &save_ptr);
|
||||
buf_ptr = NULL;
|
||||
if (!token)
|
||||
break;
|
||||
if (strncmp(token, "su", 2) == 0) {
|
||||
errno = 0;
|
||||
res = strtoul(token + 2, NULL, 10);
|
||||
if (errno == ERANGE || res > E1_RATE_MAX)
|
||||
return 0xff;
|
||||
/* Make sure the rate is a valid rate */
|
||||
for (i = 0; i < sizeof(e1_rates); i++) {
|
||||
if (res == e1_rates[i])
|
||||
return (uint8_t) res;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* Get the E1 bitstream offset from a given E1 endpoint name
|
||||
* (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
|
||||
static uint8_t e1_offs_from_epname(const char *epname)
|
||||
{
|
||||
char buf[MGCP_ENDPOINT_MAXLEN + 1];
|
||||
char *save_ptr = NULL;
|
||||
char *buf_ptr = buf;
|
||||
char *token;
|
||||
unsigned long int res = 0;
|
||||
|
||||
strncpy(buf, epname, MGCP_ENDPOINT_MAXLEN);
|
||||
|
||||
while (1) {
|
||||
token = strtok_r(buf_ptr, "/", &save_ptr);
|
||||
buf_ptr = NULL;
|
||||
if (!token)
|
||||
break;
|
||||
if (strncmp(token, "su", 2) == 0) {
|
||||
token = strstr(token, "-");
|
||||
if (!token)
|
||||
return 0xff;
|
||||
token += 1;
|
||||
errno = 0;
|
||||
res = strtoul(token, NULL, 10);
|
||||
if (errno == ERANGE || res > E1_OFFS_MAX)
|
||||
return 0xff;
|
||||
return (uint8_t) res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* Get the E1 subslot number (internal) from a given E1 endpoint name
|
||||
* (e.g. ds/e1-0/s-30/su16-4), returns 0xff on error. */
|
||||
static uint8_t e1_ss_nr_from_epname(const char *epname)
|
||||
{
|
||||
uint8_t rate;
|
||||
uint8_t offs;
|
||||
unsigned int i;
|
||||
|
||||
rate = e1_rate_from_epname(epname);
|
||||
offs = e1_offs_from_epname(epname);
|
||||
|
||||
osmo_static_assert(sizeof(e1_rates) == sizeof(e1_offsets), e1_rates_e1_offsets_size);
|
||||
|
||||
for (i = 0; i < sizeof(e1_rates); i++) {
|
||||
if ((e1_rates[i] == rate) && (e1_offsets[i] == offs))
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* Check if the selected E1 endpoint is avalable, which means that none of
|
||||
* the overlapping endpoints are currently serving a call. (if the system
|
||||
* is properly configured such a situation should never ocurr!) */
|
||||
static bool endp_avail_e1(struct mgcp_endpoint *endp)
|
||||
{
|
||||
/* The following map shows the overlapping of the subslots and their
|
||||
* respective rates. The numbers on the right running from top to bottom
|
||||
* are the bit offsets in the whole 64k timeslot. The numbers inside the
|
||||
* boxes symbolize the internal subslot number (array index) and the
|
||||
* rate in the form: i:r where i is the subslot number and r the
|
||||
* respective rate.
|
||||
*
|
||||
* +--------+--------+--------+--------+ 0
|
||||
* | | | | 7:8k |
|
||||
* | | + 3:16k +--------+ 1
|
||||
* | | | | 8:8k |
|
||||
* | | 1:32k +--------+--------+ 2
|
||||
* | | | | 9:8k |
|
||||
* | | + 4:16k +--------+ 3
|
||||
* | | | | 10:8k |
|
||||
* | 0:64k +--------+--------+--------+ 4
|
||||
* | | | | 11:8k |
|
||||
* | | + 5:16k +--------+ 5
|
||||
* | | | | 12:8k |
|
||||
* | | 2:32k +--------+--------+ 6
|
||||
* | | | | 13:8k |
|
||||
* | | + 6:16k +--------+ 7
|
||||
* | | | | 14:8k |
|
||||
* +--------+--------+--------+--------+ 8
|
||||
*
|
||||
* The following array contains tables with the subslot numbers that must be
|
||||
* unused for each subslot. During this test we do not have to check the
|
||||
* endpoint we need to verify, only the overlaps need to be checked. This is
|
||||
* also the reason why the related subslot number is missing from each each
|
||||
* line. */
|
||||
const int8_t interlock_tab[MGCP_ENDP_E1_SUBSLOTS][15] = {
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1 },
|
||||
{ 0, 3, 4, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 5, 6, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
||||
{ 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };
|
||||
|
||||
const int8_t *interlock;
|
||||
unsigned int i;
|
||||
uint8_t ts_nr = 0;
|
||||
uint8_t ss_nr = 0;
|
||||
char *epname_check;
|
||||
struct mgcp_endpoint *endp_check;
|
||||
bool available = true;
|
||||
|
||||
/* This function must only be used with E1 type endpoints! */
|
||||
OSMO_ASSERT(endp->trunk->trunk_type == MGCP_TRUNK_E1);
|
||||
|
||||
ts_nr = e1_ts_nr_from_epname(endp->name);
|
||||
ss_nr = e1_ss_nr_from_epname(endp->name);
|
||||
if (ts_nr == 0xff || ss_nr == 0xff) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"cannot check endpoint availability, endpoint name not parseable!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
interlock = interlock_tab[ss_nr];
|
||||
|
||||
for (i = 0; i < sizeof(interlock_tab[0]); i++) {
|
||||
/* Detect row end */
|
||||
if (interlock[i] == -1)
|
||||
break;
|
||||
|
||||
/* Pick overlapping endpoint to check */
|
||||
epname_check = gen_e1_epname(endp, endp->trunk->cfg->domain,
|
||||
endp->trunk->trunk_nr, ts_nr,
|
||||
interlock[i]);
|
||||
endp_check = mgcp_endp_find_specific(epname_check, endp->trunk);
|
||||
if (!endp_check) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"cannot check endpoint availability, overlapping endpoint:%s not found!\n",
|
||||
epname_check);
|
||||
talloc_free(epname_check);
|
||||
continue;
|
||||
}
|
||||
talloc_free(epname_check);
|
||||
|
||||
/* Check if overlapping endpoint currently serves another call
|
||||
* (This is an exceptional situation, that should not occur
|
||||
* in a properly configured environment!) */
|
||||
if (endp_check->callid) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"endpoint unavailable - overlapping endpoint:%s already serves a call!\n",
|
||||
endp_check->name);
|
||||
available = false;
|
||||
}
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
/*! check if an endpoint is available for any kind of operation.
|
||||
* \param[in] endp endpoint to check.
|
||||
* \returns true if endpoint is avalable, false it is blocked for any reason. */
|
||||
bool mgcp_endp_avail(struct mgcp_endpoint *endp)
|
||||
{
|
||||
switch (endp->trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
/* There are no obstacles that may render a virtual trunk
|
||||
* endpoint unusable, so virtual trunk endpoints are always
|
||||
* available */
|
||||
return true;
|
||||
case MGCP_TRUNK_E1:
|
||||
return endp_avail_e1(endp);
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! claim endpoint, sets callid and activates endpoint, should be called at the
|
||||
* beginning of the CRCX procedure when it is clear that a new call should be
|
||||
* created.
|
||||
* \param[in] endp endpoint to claim.
|
||||
* \param[in] callid that is assingned to this endpoint. */
|
||||
int mgcp_endp_claim(struct mgcp_endpoint *endp, const char *callid)
|
||||
{
|
||||
int rc = 0;
|
||||
uint8_t ts;
|
||||
uint8_t ss;
|
||||
uint8_t offs;
|
||||
|
||||
/* TODO: Make this function more intelligent, it should run the
|
||||
* call id checks we currently have in protocol.c directly here. */
|
||||
|
||||
/* Set the callid, creation of another connection will only be possible
|
||||
* when the callid matches up. (Connections are distinguished by their
|
||||
* connection ids) */
|
||||
endp->callid = talloc_strdup(endp, callid);
|
||||
OSMO_ASSERT(endp->callid);
|
||||
osmo_stat_item_inc(osmo_stat_item_group_get_item(endp->trunk->stats.common,
|
||||
TRUNK_STAT_ENDPOINTS_USED), 1);
|
||||
|
||||
/* Allocate resources */
|
||||
switch (endp->trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
/* No additional initaliziation required here, virtual
|
||||
* endpoints will open/close network sockets themselves
|
||||
* on demand. */
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
ts = e1_ts_nr_from_epname(endp->name);
|
||||
ss = e1_ss_nr_from_epname(endp->name);
|
||||
offs = e1_offs_from_epname(endp->name);
|
||||
OSMO_ASSERT(ts != 0xFF);
|
||||
OSMO_ASSERT(ts != 0);
|
||||
OSMO_ASSERT(ss != 0xFF);
|
||||
OSMO_ASSERT(offs != 0xFF);
|
||||
rc = mgcp_e1_endp_equip(endp, ts, ss, offs);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
/* Make sure the endpoint is released when claiming the endpoint fails. */
|
||||
if (rc < 0)
|
||||
mgcp_endp_release(endp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! update endpoint, updates internal endpoint specific data, should be
|
||||
* after when MDCX or CRCX has been executed successuflly.
|
||||
* \param[in] endp endpoint to update. */
|
||||
void mgcp_endp_update(struct mgcp_endpoint *endp)
|
||||
{
|
||||
/* Allocate resources */
|
||||
switch (endp->trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
/* No updating initaliziation required for virtual endpoints. */
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
mgcp_e1_endp_update(endp);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
||||
{
|
||||
llist_add(&conn->entry, &endp->conns);
|
||||
}
|
||||
|
||||
void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
|
||||
{
|
||||
/* Run endpoint cleanup action. By this we inform the endpoint about
|
||||
* the removal of the connection and allow it to clean up its inner
|
||||
* state accordingly */
|
||||
if (endp->type->cleanup_cb)
|
||||
endp->type->cleanup_cb(endp, conn);
|
||||
llist_del(&conn->entry);
|
||||
if (llist_empty(&endp->conns))
|
||||
mgcp_endp_release(endp);
|
||||
endp->wildcarded_req = false;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,11 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp_common.h>
|
||||
#include <osmocom/mgcp/mgcp_msg.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
|
||||
/*! Display an mgcp message on the log output.
|
||||
* \param[in] message mgcp message string
|
||||
@@ -85,8 +82,9 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
|
||||
int ret = 0;
|
||||
|
||||
if (!mode) {
|
||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
|
||||
"missing connection mode\n");
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x missing connection mode\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
if (!conn)
|
||||
@@ -94,35 +92,39 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
|
||||
if (!endp)
|
||||
return -1;
|
||||
|
||||
if (strcasecmp(mode, "recvonly") == 0)
|
||||
if (strcmp(mode, "recvonly") == 0)
|
||||
conn->mode = MGCP_CONN_RECV_ONLY;
|
||||
else if (strcasecmp(mode, "sendrecv") == 0)
|
||||
else if (strcmp(mode, "sendrecv") == 0)
|
||||
conn->mode = MGCP_CONN_RECV_SEND;
|
||||
else if (strcasecmp(mode, "sendonly") == 0)
|
||||
else if (strcmp(mode, "sendonly") == 0)
|
||||
conn->mode = MGCP_CONN_SEND_ONLY;
|
||||
else if (strcasecmp(mode, "loopback") == 0)
|
||||
else if (strcmp(mode, "loopback") == 0)
|
||||
conn->mode = MGCP_CONN_LOOPBACK;
|
||||
else {
|
||||
LOGPCONN(conn, DLMGCP, LOGL_ERROR,
|
||||
"unknown connection mode: '%s'\n", mode);
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x unknown connection mode: '%s'\n",
|
||||
ENDPOINT_NUMBER(endp), mode);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
/* Special handling for RTP connections */
|
||||
/* Special handling für RTP connections */
|
||||
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
||||
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));
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"endpoint:0x%x conn:%s\n",
|
||||
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn));
|
||||
|
||||
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n",
|
||||
mode, conn->mode);
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"endpoint:0x%x connection mode '%s' %d\n",
|
||||
ENDPOINT_NUMBER(endp), mode, conn->mode);
|
||||
|
||||
/* Special handling für RTP connections */
|
||||
if (conn->type == MGCP_CONN_TYPE_RTP) {
|
||||
LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %d\n",
|
||||
conn->u.rtp.end.output_enabled);
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "endpoint:0x%x output_enabled %d\n",
|
||||
ENDPOINT_NUMBER(endp), conn->u.rtp.end.output_enabled);
|
||||
}
|
||||
|
||||
/* The VTY might change the connection mode at any time, so we have
|
||||
@@ -132,20 +134,186 @@ int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We have a null terminated string with the endpoint name here. We only
|
||||
* support two kinds. Simple ones as seen on the BSC level and the ones
|
||||
* seen on the trunk side. (helper function for find_endpoint()) */
|
||||
static struct mgcp_endpoint *find_e1_endpoint(struct mgcp_config *cfg,
|
||||
const char *mgcp)
|
||||
{
|
||||
char *rest = NULL;
|
||||
struct mgcp_trunk_config *tcfg;
|
||||
int trunk, endp;
|
||||
struct mgcp_endpoint *endp_ptr;
|
||||
|
||||
trunk = strtoul(mgcp + 6, &rest, 10);
|
||||
if (rest == NULL || rest[0] != '/' || trunk < 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Wrong trunk name '%s'\n", mgcp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
endp = strtoul(rest + 1, &rest, 10);
|
||||
if (rest == NULL || rest[0] != '@') {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Wrong endpoint name '%s'\n", mgcp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* signalling is on timeslot 1 */
|
||||
if (endp == 1)
|
||||
return NULL;
|
||||
|
||||
tcfg = mgcp_trunk_num(cfg, trunk);
|
||||
if (!tcfg) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "The trunk %d is not declared.\n",
|
||||
trunk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!tcfg->endpoints) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Endpoints of trunk %d not allocated.\n", trunk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (endp < 1 || endp >= tcfg->number_endpoints) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Failed to find endpoint '%s'\n",
|
||||
mgcp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
endp_ptr = &tcfg->endpoints[endp];
|
||||
endp_ptr->wildcarded_req = false;
|
||||
return endp_ptr;
|
||||
}
|
||||
|
||||
/* Find an endpoint that is not in use. Do this by going through the endpoint
|
||||
* array, check the callid. A callid nullpointer indicates that the endpoint
|
||||
* is free */
|
||||
static struct mgcp_endpoint *find_free_endpoint(struct mgcp_endpoint *endpoints,
|
||||
unsigned int number_endpoints)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < number_endpoints; i++) {
|
||||
if (endpoints[i].callid == NULL) {
|
||||
endp = &endpoints[i];
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"endpoint:0x%x found free endpoint\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
endp->wildcarded_req = true;
|
||||
return endp;
|
||||
}
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Not able to find a free endpoint\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if the domain name, which is supplied with the endpoint name
|
||||
* matches the configuration. */
|
||||
static int check_domain_name(struct mgcp_config *cfg, const char *mgcp)
|
||||
{
|
||||
char *domain_to_check;
|
||||
|
||||
domain_to_check = strstr(mgcp, "@");
|
||||
if (!domain_to_check)
|
||||
return -EINVAL;
|
||||
|
||||
/* Accept any domain if configured as "*" */
|
||||
if (!strcmp(cfg->domain, "*"))
|
||||
return 0;
|
||||
|
||||
if (strcmp(domain_to_check+1, cfg->domain) != 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Wrong domain name '%s', expecting '%s'\n", mgcp, cfg->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search the endpoint pool for the endpoint that had been selected via the
|
||||
* MGCP message (helper function for mgcp_analyze_header()) */
|
||||
static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg,
|
||||
const char *mgcp,
|
||||
int *cause)
|
||||
{
|
||||
char *endptr = NULL;
|
||||
unsigned int gw = INT_MAX;
|
||||
const char *endpoint_number_str;
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
*cause = 0;
|
||||
|
||||
/* Check if the domainname in the request is correct */
|
||||
if (check_domain_name(cfg, mgcp)) {
|
||||
*cause = -500;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if the E1 trunk is requested */
|
||||
if (strncmp(mgcp, "ds/e1", 5) == 0) {
|
||||
endp = find_e1_endpoint(cfg, mgcp);
|
||||
if (!endp)
|
||||
*cause = -500;
|
||||
return endp;
|
||||
}
|
||||
|
||||
/* Check if the virtual trunk is addressed (new, correct way with prefix) */
|
||||
if (strncmp
|
||||
(mgcp, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK,
|
||||
strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK)) == 0) {
|
||||
endpoint_number_str =
|
||||
mgcp + strlen(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
|
||||
if (endpoint_number_str[0] == '*') {
|
||||
endp = find_free_endpoint(cfg->trunk.endpoints,
|
||||
cfg->trunk.number_endpoints);
|
||||
if (!endp)
|
||||
*cause = -403;
|
||||
return endp;
|
||||
}
|
||||
gw = strtoul(endpoint_number_str, &endptr, 16);
|
||||
if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
|
||||
endp = &cfg->trunk.endpoints[gw];
|
||||
endp->wildcarded_req = false;
|
||||
return endp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deprecated method without prefix */
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Addressing virtual trunk without prefix (deprecated), please use %s: '%s'\n",
|
||||
MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, mgcp);
|
||||
gw = strtoul(mgcp, &endptr, 16);
|
||||
if (gw < cfg->trunk.number_endpoints && endptr[0] == '@') {
|
||||
endp = &cfg->trunk.endpoints[gw];
|
||||
endp->wildcarded_req = false;
|
||||
return endp;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
|
||||
*cause = -500;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Analyze and parse the the hader of an MGCP messeage string.
|
||||
* \param[out] pdata caller provided memory to store the parsing results.
|
||||
* \param[in] data mgcp message string.
|
||||
* \returns 0 when the status line was complete and parseable, negative (MGCP
|
||||
* cause code) on error. */
|
||||
* \param[out] pdata caller provided memory to store the parsing results
|
||||
* \param[in] data mgcp message string
|
||||
* \returns when the status line was complete and transaction_id and
|
||||
* endp out parameters are set, -1 on error */
|
||||
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
||||
{
|
||||
int i = 0;
|
||||
char *elem, *save = NULL;
|
||||
int cause;
|
||||
|
||||
/*! This function will parse the header part of the received
|
||||
* MGCP message. The parsing results are stored in pdata. */
|
||||
* MGCP message. The parsing results are stored in pdata.
|
||||
* The function will also automatically search the pool with
|
||||
* available endpoints in order to find an endpoint that matches
|
||||
* the endpoint string in in the header */
|
||||
|
||||
OSMO_ASSERT(data);
|
||||
pdata->trans = "000000";
|
||||
|
||||
for (elem = strtok_r(data, " ", &save); elem;
|
||||
elem = strtok_r(NULL, " ", &save)) {
|
||||
@@ -154,18 +322,27 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
||||
pdata->trans = elem;
|
||||
break;
|
||||
case 1:
|
||||
pdata->epname = elem;
|
||||
pdata->endp = find_endpoint(pdata->cfg, elem, &cause);
|
||||
if (!pdata->endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Unable to find Endpoint `%s'\n", elem);
|
||||
OSMO_ASSERT(cause < 0);
|
||||
return cause;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (strcasecmp("MGCP", elem)) {
|
||||
if (strcmp("MGCP", elem)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"MGCP header parsing error\n");
|
||||
return -510;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (strcmp("1.0", elem))
|
||||
if (strcmp("1.0", elem)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
|
||||
"not supported\n", elem);
|
||||
return -528;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
@@ -173,6 +350,8 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
||||
|
||||
if (i != 4) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
|
||||
pdata->trans = "000000";
|
||||
pdata->endp = NULL;
|
||||
return -510;
|
||||
}
|
||||
|
||||
@@ -181,27 +360,18 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data)
|
||||
|
||||
/*! Extract OSMUX CID from an MGCP parameter line (string).
|
||||
* \param[in] line single parameter line from the MGCP message
|
||||
* \returns OSMUX CID, -1 wildcard, -2 on error */
|
||||
* \returns OSMUX CID, -1 on error */
|
||||
int mgcp_parse_osmux_cid(const char *line)
|
||||
{
|
||||
int osmux_cid;
|
||||
|
||||
|
||||
if (strcasecmp(line + 2, "Osmux: *") == 0) {
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n");
|
||||
if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n",
|
||||
line);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (osmux_cid > OSMUX_CID_MAX) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
|
||||
osmux_cid, OSMUX_CID_MAX);
|
||||
return -2;
|
||||
return -1;
|
||||
}
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
|
||||
|
||||
@@ -209,30 +379,28 @@ int mgcp_parse_osmux_cid(const char *line)
|
||||
}
|
||||
|
||||
/*! Check MGCP parameter line (string) for plausibility.
|
||||
* \param[in] endp pointer to endpoint (only used for log output, may be NULL)
|
||||
* \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL)
|
||||
* \param[in] endp pointer to endpoint (only used for log output)
|
||||
* \param[in] line single parameter line from the MGCP message
|
||||
* \returns true when line seems plausible, false on error */
|
||||
bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line)
|
||||
* \returns 1 when line seems plausible, 0 on error */
|
||||
int mgcp_check_param(const struct mgcp_endpoint *endp, const char *line)
|
||||
{
|
||||
const size_t line_len = strlen(line);
|
||||
if (line[0] != '\0' && line_len < 2) {
|
||||
if (endp)
|
||||
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
|
||||
else
|
||||
LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line);
|
||||
return false;
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Wrong MGCP option format: '%s' on 0x%x\n",
|
||||
line, ENDPOINT_NUMBER(endp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: A couple more checks wouldn't hurt... */
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*! Check if the specified callid seems plausible.
|
||||
* \param[in] endp pointer to endpoint
|
||||
* \param{in] callid to verify
|
||||
* \returns 0 when callid seems plausible, -1 on error */
|
||||
* \returns 1 when callid seems plausible, 0 on error */
|
||||
int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
|
||||
{
|
||||
/*! This function compares the supplied callid with the called that is
|
||||
@@ -251,9 +419,9 @@ int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid)
|
||||
return -1;
|
||||
|
||||
if (strcmp(endp->callid, callid) != 0) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"CallIDs mismatch: '%s' != '%s'\n",
|
||||
endp->callid, callid);
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x CallIDs mismatch: '%s' != '%s'\n",
|
||||
ENDPOINT_NUMBER(endp), endp->callid, callid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -272,23 +440,25 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
|
||||
|
||||
/* Check for null identifiers */
|
||||
if (!conn_id) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"invalid ConnectionIdentifier (missing)\n");
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x invalid ConnectionIdentifier (missing)\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return 510;
|
||||
}
|
||||
|
||||
/* Check for empty connection identifiers */
|
||||
if (strlen(conn_id) == 0) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"invalid ConnectionIdentifier (empty)\n");
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x invalid ConnectionIdentifier (empty)\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return 510;
|
||||
}
|
||||
|
||||
/* Check for over long connection identifiers */
|
||||
if (strlen(conn_id) > (MGCP_CONN_ID_MAXLEN-1)) {
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"invalid ConnectionIdentifier (too long: %zu > %d) 0x%s\n",
|
||||
strlen(conn_id), MGCP_CONN_ID_MAXLEN-1, conn_id);
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x invalid ConnectionIdentifier (too long: %zu > %d) 0x%s\n",
|
||||
ENDPOINT_NUMBER(endp), strlen(conn_id), MGCP_CONN_ID_MAXLEN-1, conn_id);
|
||||
return 510;
|
||||
}
|
||||
|
||||
@@ -296,8 +466,9 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
|
||||
if (mgcp_conn_get(endp, conn_id))
|
||||
return 0;
|
||||
|
||||
LOGPENDP(endp, DLMGCP, LOGL_ERROR,
|
||||
"no connection found under ConnectionIdentifier 0x%s\n", conn_id);
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"endpoint:0x%x no connection found under ConnectionIdentifier 0x%s\n",
|
||||
ENDPOINT_NUMBER(endp), conn_id);
|
||||
|
||||
/* When the conn_id was not found, return error code 515 "The transaction refers to an incorrect
|
||||
* connection-id (may have been already deleted)." */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,19 +15,16 @@
|
||||
#include <inttypes.h> /* for PRIu64 */
|
||||
#include <netinet/in.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
#include <osmocom/netif/osmux.h>
|
||||
#include <osmocom/netif/rtp.h>
|
||||
#include <osmocom/netif/amr.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
|
||||
static struct osmo_fd osmux_fd;
|
||||
|
||||
@@ -35,10 +32,9 @@ static LLIST_HEAD(osmux_handle_list);
|
||||
|
||||
struct osmux_handle {
|
||||
struct llist_head head;
|
||||
struct mgcp_conn_rtp *conn;
|
||||
struct osmux_in_handle *in;
|
||||
struct in_addr rem_addr;
|
||||
int rem_port; /* network byte order */
|
||||
int rem_port;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
@@ -48,17 +44,14 @@ static void *osmux;
|
||||
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
|
||||
{
|
||||
struct osmux_handle *handle = data;
|
||||
struct mgcp_conn_rtp *conn = handle->conn;
|
||||
struct sockaddr_in out = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = handle->rem_port,
|
||||
};
|
||||
|
||||
if (conn->end.output_enabled) {
|
||||
struct sockaddr_in out = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = handle->rem_port,
|
||||
};
|
||||
memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
|
||||
sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
|
||||
(struct sockaddr *)&out, sizeof(out));
|
||||
}
|
||||
memcpy(&out.sin_addr, &handle->rem_addr, sizeof(handle->rem_addr));
|
||||
sendto(osmux_fd.fd, batch_msg->data, batch_msg->len, 0,
|
||||
(struct sockaddr *)&out, sizeof(out));
|
||||
msgb_free(batch_msg);
|
||||
}
|
||||
|
||||
@@ -113,15 +106,13 @@ static void osmux_handle_put(struct osmux_in_handle *in)
|
||||
|
||||
/* Allocate free OSMUX handle */
|
||||
static struct osmux_handle *
|
||||
osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_port)
|
||||
osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
struct mgcp_config *cfg = conn->conn->endp->trunk->cfg;
|
||||
|
||||
h = talloc_zero(osmux, struct osmux_handle);
|
||||
if (!h)
|
||||
return NULL;
|
||||
h->conn = conn;
|
||||
h->rem_addr = *addr;
|
||||
h->rem_port = rem_port;
|
||||
h->refcnt++;
|
||||
@@ -154,20 +145,15 @@ osmux_handle_alloc(struct mgcp_conn_rtp *conn, struct in_addr *addr, int rem_por
|
||||
/* Lookup existing handle for a specified address, if the handle can not be
|
||||
* found, the function will automatically allocate one */
|
||||
static struct osmux_in_handle *
|
||||
osmux_handle_lookup(struct mgcp_conn_rtp *conn, struct osmo_sockaddr *addr, int rem_port)
|
||||
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
|
||||
{
|
||||
struct osmux_handle *h;
|
||||
|
||||
if (addr->u.sa.sa_family != AF_INET) {
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "IPv6 not supported in osmux yet!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h = osmux_handle_find_get(&addr->u.sin.sin_addr, rem_port);
|
||||
h = osmux_handle_find_get(addr, rem_port);
|
||||
if (h != NULL)
|
||||
return h->in;
|
||||
|
||||
h = osmux_handle_alloc(conn, &addr->u.sin.sin_addr, rem_port);
|
||||
h = osmux_handle_alloc(cfg, addr, rem_port);
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -191,12 +177,6 @@ int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
|
||||
memcpy(msg->data, buf, buf_len);
|
||||
msgb_put(msg, buf_len);
|
||||
|
||||
if (conn->osmux.state != OSMUX_STATE_ENABLED) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO, "forwarding RTP to Osmux conn not yet enabled, dropping (cid=%d)\n",
|
||||
conn->osmux.cid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((ret = osmux_xfrm_input(conn->osmux.in, msg, conn->osmux.cid)) > 0) {
|
||||
/* batch full, build and deliver it */
|
||||
osmux_xfrm_input_deliver(conn->osmux.in);
|
||||
@@ -205,57 +185,109 @@ int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
|
||||
}
|
||||
|
||||
/* Lookup the endpoint that corresponds to the specified address (port) */
|
||||
static struct mgcp_conn_rtp*
|
||||
osmux_conn_lookup(struct mgcp_config *cfg, uint8_t cid,
|
||||
struct in_addr *from_addr)
|
||||
static struct mgcp_endpoint *
|
||||
endpoint_lookup(struct mgcp_config *cfg, int cid,
|
||||
struct in_addr *from_addr, int type)
|
||||
{
|
||||
struct mgcp_trunk *trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
struct mgcp_endpoint *endp;
|
||||
struct mgcp_conn *conn = NULL;
|
||||
struct mgcp_conn_rtp * conn_rtp;
|
||||
struct mgcp_endpoint *endp = NULL;
|
||||
int i;
|
||||
struct mgcp_conn_rtp *conn_net = NULL;
|
||||
struct mgcp_conn_rtp *conn_bts = NULL;
|
||||
|
||||
for (i = 0; i < trunk->number_endpoints; i++) {
|
||||
for (i=0; i<cfg->trunk.number_endpoints; i++) {
|
||||
struct in_addr *this;
|
||||
|
||||
endp = trunk->endpoints[i];
|
||||
endp = &cfg->trunk.endpoints[i];
|
||||
|
||||
llist_for_each_entry(conn, &endp->conns, entry) {
|
||||
if (conn->type != MGCP_CONN_TYPE_RTP)
|
||||
continue;
|
||||
#if 0
|
||||
if (!tmp->allocated)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
conn_rtp = &conn->u.rtp;
|
||||
if (!mgcp_conn_rtp_is_osmux(conn_rtp))
|
||||
continue;
|
||||
|
||||
if (conn_rtp->osmux.cid == cid)
|
||||
return conn_rtp;
|
||||
switch(type) {
|
||||
case MGCP_DEST_NET:
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
|
||||
if (conn_net)
|
||||
this = &conn_net->end.addr;
|
||||
else
|
||||
this = NULL;
|
||||
break;
|
||||
case MGCP_DEST_BTS:
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
|
||||
if (conn_bts)
|
||||
this = &conn_bts->end.addr;
|
||||
else
|
||||
this = NULL;
|
||||
break;
|
||||
default:
|
||||
/* Should not ever happen */
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Bad type %d. Fix your code.\n", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
|
||||
if (conn_net && this && conn_net->osmux.cid == cid
|
||||
&& this->s_addr == from_addr->s_addr)
|
||||
return endp;
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot find osmux conn with cid=%d\n", cid);
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot find endpoint with cid=%d\n", cid);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: this is declared and used in mgcp_network.c, but documentation of mgcp_dispatch_rtp_bridge_cb() states another enum is to be used */
|
||||
enum {
|
||||
MGCP_PROTO_RTP,
|
||||
MGCP_PROTO_RTCP,
|
||||
};
|
||||
|
||||
static void scheduled_from_osmux_tx_rtp_cb(struct msgb *msg, void *data)
|
||||
static void scheduled_tx_net_cb(struct msgb *msg, void *data)
|
||||
{
|
||||
struct mgcp_conn_rtp *conn = data;
|
||||
struct mgcp_endpoint *endp = conn->conn->endp;
|
||||
struct osmo_sockaddr addr = { /* FIXME: do we know the source address?? */ };
|
||||
struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
|
||||
*mc = (struct osmo_rtp_msg_ctx){
|
||||
.proto = MGCP_PROTO_RTP,
|
||||
.conn_src = conn,
|
||||
.from_addr = &addr,
|
||||
struct mgcp_endpoint *endp = data;
|
||||
struct mgcp_conn_rtp *conn_net = NULL;
|
||||
struct mgcp_conn_rtp *conn_bts = NULL;
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
|
||||
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
|
||||
if (!conn_bts || !conn_net)
|
||||
return;
|
||||
|
||||
struct sockaddr_in addr = {
|
||||
.sin_addr = conn_net->end.addr,
|
||||
.sin_port = conn_net->end.rtp_port,
|
||||
};
|
||||
|
||||
endp->type->dispatch_rtp_cb(msg);
|
||||
rate_ctr_inc(&conn_bts->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
|
||||
rate_ctr_add(&conn_bts->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], msg->len);
|
||||
|
||||
/* Send RTP data to NET */
|
||||
/* FIXME: Get rid of conn_bts and conn_net! */
|
||||
mgcp_send(endp, 1, &addr, msg, conn_bts, conn_net);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
|
||||
{
|
||||
struct mgcp_endpoint *endp = data;
|
||||
struct mgcp_conn_rtp *conn_net = NULL;
|
||||
struct mgcp_conn_rtp *conn_bts = NULL;
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
|
||||
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
|
||||
if (!conn_bts || !conn_net)
|
||||
return;
|
||||
|
||||
struct sockaddr_in addr = {
|
||||
.sin_addr = conn_bts->end.addr,
|
||||
.sin_port = conn_bts->end.rtp_port,
|
||||
};
|
||||
|
||||
rate_ctr_inc(&conn_net->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
|
||||
rate_ctr_add(&conn_net->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], msg->len);
|
||||
|
||||
/* Send RTP data to BTS */
|
||||
/* FIXME: Get rid of conn_bts and conn_net! */
|
||||
mgcp_send(endp, 1, &addr, msg, conn_net, conn_bts);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
@@ -286,31 +318,26 @@ static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
|
||||
static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
bool sending)
|
||||
{
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
|
||||
switch(conn->osmux.state) {
|
||||
case OSMUX_STATE_ACTIVATING:
|
||||
if (osmux_enable_conn(endp, conn, &conn->end.addr, conn->end.rtp_port) < 0) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"Could not enable osmux for conn on %s: %s\n",
|
||||
sending ? "sent" : "received",
|
||||
mgcp_conn_dump(conn->conn));
|
||||
if (osmux_enable_conn(endp, conn, &conn->end.addr, htons(endp->cfg->osmux_port)) < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Could not enable osmux for conn:%s\n",
|
||||
mgcp_conn_dump(conn->conn));
|
||||
return -1;
|
||||
}
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"Osmux %s CID %u towards %s:%u is now enabled\n",
|
||||
sending ? "sent" : "received",
|
||||
conn->osmux.cid,
|
||||
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
|
||||
ntohs(conn->end.rtp_port));
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Osmux CID %u for %s:%u is now enabled\n",
|
||||
conn->osmux.cid, inet_ntoa(conn->end.addr),
|
||||
endp->cfg->osmux_port);
|
||||
return 0;
|
||||
case OSMUX_STATE_ENABLED:
|
||||
return 0;
|
||||
default:
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"Osmux %s in conn %s without full negotiation, state %d\n",
|
||||
sending ? "sent" : "received",
|
||||
mgcp_conn_dump(conn->conn), conn->osmux.state);
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Osmux %s in conn %s without full negotiation, state %d\n",
|
||||
sending ? "sent" : "received",
|
||||
mgcp_conn_dump(conn->conn), conn->osmux.state);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -318,9 +345,9 @@ static int endp_osmux_state_check(struct mgcp_endpoint *endp, struct mgcp_conn_r
|
||||
static int osmux_legacy_dummy_parse_cid(struct sockaddr_in *addr, struct msgb *msg,
|
||||
uint8_t *osmux_cid)
|
||||
{
|
||||
if (msg->len < 1 + sizeof(*osmux_cid)) {
|
||||
if (msg->len < 1 + sizeof(osmux_cid)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Discarding truncated Osmux dummy load: %s\n", osmo_hexdump(msg->data, msg->len));
|
||||
"Discarding truncated Osmux dummy load\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -329,40 +356,16 @@ static int osmux_legacy_dummy_parse_cid(struct sockaddr_in *addr, struct msgb *m
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is called from the bsc-nat */
|
||||
static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
|
||||
struct msgb *msg)
|
||||
{
|
||||
uint8_t osmux_cid;
|
||||
struct mgcp_conn_rtp *conn;
|
||||
|
||||
if (osmux_legacy_dummy_parse_cid(addr, msg, &osmux_cid) < 0)
|
||||
goto out;
|
||||
|
||||
conn = osmux_conn_lookup(cfg, osmux_cid, &addr->sin_addr);
|
||||
if (!conn) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find conn for Osmux CID %d\n", osmux_cid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
endp_osmux_state_check(conn->conn->endp, conn, false);
|
||||
/* Only needed to punch hole in firewall, it can be dropped */
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define osmux_chunk_length(msg, rem) (rem - msg->len);
|
||||
|
||||
static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmux_hdr *osmuxh;
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_config *cfg = ofd->data;
|
||||
uint32_t rem;
|
||||
struct mgcp_conn_rtp *conn_src;
|
||||
struct mgcp_conn_rtp *conn_bts = NULL;
|
||||
|
||||
msg = osmux_recv(ofd, &addr);
|
||||
if (!msg)
|
||||
@@ -375,35 +378,116 @@ static int osmux_read_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
}
|
||||
|
||||
/* not any further processing dummy messages */
|
||||
if (mgcp_is_rtp_dummy_payload(msg))
|
||||
return osmux_handle_dummy(cfg, &addr, msg);
|
||||
if (msg->data[0] == MGCP_DUMMY_LOAD)
|
||||
goto out;
|
||||
|
||||
rem = msg->len;
|
||||
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
conn_src = osmux_conn_lookup(cfg, osmuxh->circuit_id,
|
||||
&addr.sin_addr);
|
||||
if (!conn_src) {
|
||||
/* Yes, we use MGCP_DEST_NET to locate the origin */
|
||||
endp = endpoint_lookup(cfg, osmuxh->circuit_id,
|
||||
&addr.sin_addr, MGCP_DEST_NET);
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_bts = mgcp_conn_get_rtp(endp, CONN_ID_BTS);
|
||||
if (!conn_bts)
|
||||
continue;
|
||||
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find a src conn for circuit_id=%d\n",
|
||||
"Cannot find an endpoint for circuit_id=%d\n",
|
||||
osmuxh->circuit_id);
|
||||
goto out;
|
||||
}
|
||||
if (endp_osmux_state_check(endp, conn_bts, false) == 0) {
|
||||
conn_bts->osmux.stats.octets += osmux_chunk_length(msg, rem);
|
||||
conn_bts->osmux.stats.chunks++;
|
||||
osmux_xfrm_output_sched(&conn_bts->osmux.out, osmuxh);
|
||||
}
|
||||
rem = msg->len;
|
||||
}
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mgcp_conn_watchdog_kick(conn_src->conn);
|
||||
/* This is called from the bsc-nat */
|
||||
static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
|
||||
struct msgb *msg, int endp_type)
|
||||
{
|
||||
struct mgcp_endpoint *endp;
|
||||
uint8_t osmux_cid;
|
||||
struct mgcp_conn_rtp *conn = NULL;
|
||||
|
||||
/*conn_dst = mgcp_find_dst_conn(conn_src->conn);
|
||||
if (!conn_dst) {
|
||||
if (osmux_legacy_dummy_parse_cid(addr, msg, &osmux_cid) < 0)
|
||||
goto out;
|
||||
|
||||
endp = endpoint_lookup(cfg, osmux_cid, &addr->sin_addr, endp_type);
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find endpoint for Osmux CID %d\n", osmux_cid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn = mgcp_conn_get_rtp(endp, endp_type == MGCP_DEST_BTS ? CONN_ID_NET : CONN_ID_BTS);
|
||||
if (!conn)
|
||||
goto out;
|
||||
|
||||
endp_osmux_state_check(endp, conn, false);
|
||||
/* Only needed to punch hole in firewall, it can be dropped */
|
||||
out:
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmux_read_from_bsc_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmux_hdr *osmuxh;
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_config *cfg = ofd->data;
|
||||
uint32_t rem;
|
||||
struct mgcp_conn_rtp *conn_net = NULL;
|
||||
|
||||
msg = osmux_recv(ofd, &addr);
|
||||
if (!msg)
|
||||
return -1;
|
||||
|
||||
if (!cfg->osmux) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"bsc wants to use Osmux but bsc-nat did not request it\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* not any further processing dummy messages */
|
||||
if (msg->data[0] == MGCP_DUMMY_LOAD)
|
||||
return osmux_handle_dummy(cfg, &addr, msg, MGCP_DEST_BTS);
|
||||
|
||||
rem = msg->len;
|
||||
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
|
||||
struct mgcp_endpoint *endp;
|
||||
|
||||
/* Yes, we use MGCP_DEST_BTS to locate the origin */
|
||||
endp = endpoint_lookup(cfg, osmuxh->circuit_id,
|
||||
&addr.sin_addr, MGCP_DEST_BTS);
|
||||
|
||||
/* FIXME: Get rid of CONN_ID_XXX! */
|
||||
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
|
||||
if (!conn_net)
|
||||
continue;
|
||||
|
||||
if (!endp) {
|
||||
LOGP(DLMGCP, LOGL_ERROR,
|
||||
"Cannot find a dst conn for circuit_id=%d\n",
|
||||
"Cannot find an endpoint for circuit_id=%d\n",
|
||||
osmuxh->circuit_id);
|
||||
goto out;
|
||||
}*/
|
||||
|
||||
if (endp_osmux_state_check(conn_src->conn->endp, conn_src, false) == 0) {
|
||||
conn_src->osmux.stats.octets += osmux_chunk_length(msg, rem);
|
||||
conn_src->osmux.stats.chunks++;
|
||||
osmux_xfrm_output_sched(&conn_src->osmux.out, osmuxh);
|
||||
}
|
||||
if (endp_osmux_state_check(endp, conn_net, false) == 0) {
|
||||
conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
|
||||
conn_net->osmux.stats.chunks++;
|
||||
osmux_xfrm_output_sched(&conn_net->osmux.out, osmuxh);
|
||||
}
|
||||
rem = msg->len;
|
||||
}
|
||||
@@ -416,27 +500,34 @@ int osmux_init(int role, struct mgcp_config *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
osmo_fd_setup(&osmux_fd, -1, OSMO_FD_READ, osmux_read_fd_cb, cfg, 0);
|
||||
switch(role) {
|
||||
case OSMUX_ROLE_BSC:
|
||||
osmux_fd.cb = osmux_read_from_bsc_nat_cb;
|
||||
break;
|
||||
case OSMUX_ROLE_BSC_NAT:
|
||||
osmux_fd.cb = osmux_read_from_bsc_cb;
|
||||
break;
|
||||
default:
|
||||
LOGP(DLMGCP, LOGL_ERROR, "wrong role for OSMUX\n");
|
||||
return -1;
|
||||
}
|
||||
osmux_fd.data = cfg;
|
||||
|
||||
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port,
|
||||
cfg->endp_dscp, cfg->endp_priority);
|
||||
ret = mgcp_create_bind(cfg->osmux_addr, &osmux_fd, cfg->osmux_port);
|
||||
if (ret < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket to %s:%u\n",
|
||||
cfg->osmux_addr, cfg->osmux_port);
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot bind OSMUX socket\n");
|
||||
return ret;
|
||||
}
|
||||
mgcp_set_ip_tos(osmux_fd.fd, cfg->endp_dscp);
|
||||
osmux_fd.when |= BSC_FD_READ;
|
||||
|
||||
ret = osmo_fd_register(&osmux_fd);
|
||||
if (ret < 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot register OSMUX socket %s\n",
|
||||
osmo_sock_get_name2(osmux_fd.fd));
|
||||
LOGP(DLMGCP, LOGL_ERROR, "cannot register OSMUX socket\n");
|
||||
return ret;
|
||||
}
|
||||
cfg->osmux_init = 1;
|
||||
|
||||
LOGP(DLMGCP, LOGL_INFO, "OSMUX socket listening on %s\n",
|
||||
osmo_sock_get_name2(osmux_fd.fd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -444,10 +535,10 @@ int osmux_init(int role, struct mgcp_config *cfg)
|
||||
* \param[in] endp mgcp endpoint (configuration)
|
||||
* \param[in] conn connection to disable
|
||||
* \param[in] addr IP address of remote OSMUX endpoint
|
||||
* \param[in] port portnumber of the remote OSMUX endpoint (in network byte order)
|
||||
* \param[in] port portnumber of the remote OSMUX endpoint
|
||||
* \returns 0 on success, -1 on ERROR */
|
||||
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
struct osmo_sockaddr *addr, uint16_t port)
|
||||
struct in_addr *addr, uint16_t port)
|
||||
{
|
||||
/*! If osmux is enabled, initialize the output handler. This handler is
|
||||
* used to reconstruct the RTP flow from osmux. The RTP SSRC is
|
||||
@@ -458,49 +549,44 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
* overlapping RTP SSRC traveling to the BTSes behind the BSC,
|
||||
* similarly, for flows traveling to the MSC.
|
||||
*/
|
||||
struct in6_addr addr_unset = {};
|
||||
static const uint32_t rtp_ssrc_winlen = UINT32_MAX / (OSMUX_CID_MAX + 1);
|
||||
uint16_t osmux_dummy = endp->trunk->cfg->osmux_dummy;
|
||||
uint16_t osmux_dummy = endp->cfg->osmux_dummy;
|
||||
|
||||
/* Check if osmux is enabled for the specified connection */
|
||||
if (conn->osmux.state != OSMUX_STATE_ACTIVATING) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"conn:%s didn't negotiate Osmux, state %d\n",
|
||||
mgcp_conn_dump(conn->conn), conn->osmux.state);
|
||||
LOGP(DLMGCP, LOGL_ERROR, "conn:%s didn't negotiate Osmux, state %d\n",
|
||||
mgcp_conn_dump(conn->conn), conn->osmux.state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait until we have the connection information from MDCX */
|
||||
if (memcmp(&conn->end.addr, &addr_unset,
|
||||
conn->end.addr.u.sa.sa_family == AF_INET6 ?
|
||||
sizeof(struct in6_addr) :
|
||||
sizeof(struct in_addr)) == 0) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
|
||||
"Osmux remote address/port still unknown\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn->osmux.in = osmux_handle_lookup(conn, addr, port);
|
||||
conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
|
||||
if (!conn->osmux.in) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"Cannot allocate input osmux handle for conn:%s\n",
|
||||
mgcp_conn_dump(conn->conn));
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot allocate input osmux handle for conn:%s\n",
|
||||
mgcp_conn_dump(conn->conn));
|
||||
return -1;
|
||||
}
|
||||
if (osmux_xfrm_input_open_circuit(conn->osmux.in, conn->osmux.cid, osmux_dummy) < 0) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
|
||||
"Cannot open osmux circuit %u for conn:%s\n",
|
||||
if (!osmux_xfrm_input_open_circuit(conn->osmux.in, conn->osmux.cid, osmux_dummy)) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u for conn:%s\n",
|
||||
conn->osmux.cid, mgcp_conn_dump(conn->conn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
osmux_xfrm_output_init2(&conn->osmux.out,
|
||||
osmux_xfrm_output_init(&conn->osmux.out,
|
||||
(conn->osmux.cid * rtp_ssrc_winlen) +
|
||||
(random() % rtp_ssrc_winlen),
|
||||
conn->end.codec->payload_type);
|
||||
(random() % rtp_ssrc_winlen));
|
||||
|
||||
osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
|
||||
scheduled_from_osmux_tx_rtp_cb, conn);
|
||||
switch (endp->cfg->role) {
|
||||
case MGCP_BSC_NAT:
|
||||
conn->type = MGCP_OSMUX_BSC_NAT;
|
||||
osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
|
||||
scheduled_tx_net_cb, endp);
|
||||
break;
|
||||
case MGCP_BSC:
|
||||
conn->type = MGCP_OSMUX_BSC;
|
||||
osmux_xfrm_output_set_tx_cb(&conn->osmux.out,
|
||||
scheduled_tx_bts_cb, endp);
|
||||
break;
|
||||
}
|
||||
|
||||
conn->osmux.state = OSMUX_STATE_ENABLED;
|
||||
|
||||
@@ -509,65 +595,48 @@ int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
|
||||
|
||||
/*! disable OSXMUX circuit for a specified connection.
|
||||
* \param[in] conn connection to disable */
|
||||
void conn_osmux_disable(struct mgcp_conn_rtp *conn)
|
||||
void osmux_disable_conn(struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
OSMO_ASSERT(conn->osmux.state != OSMUX_STATE_DISABLED);
|
||||
if (conn->osmux.state != OSMUX_STATE_ENABLED)
|
||||
return;
|
||||
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
|
||||
"Releasing connection using Osmux CID %u\n", conn->osmux.cid);
|
||||
LOGP(DLMGCP, LOGL_INFO, "Releasing connection %s using Osmux CID %u\n",
|
||||
conn->conn->id, conn->osmux.cid);
|
||||
|
||||
if (conn->osmux.state == OSMUX_STATE_ENABLED) {
|
||||
/* We are closing, we don't need pending RTP packets to be transmitted */
|
||||
osmux_xfrm_output_set_tx_cb(&conn->osmux.out, NULL, NULL);
|
||||
osmux_xfrm_output_flush(&conn->osmux.out);
|
||||
/* We are closing, we don't need pending RTP packets to be transmitted */
|
||||
osmux_xfrm_output_set_tx_cb(&conn->osmux.out, NULL, NULL);
|
||||
osmux_xfrm_output_flush(&conn->osmux.out);
|
||||
|
||||
osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
|
||||
conn->osmux.state = OSMUX_STATE_DISABLED;
|
||||
conn_osmux_release_cid(conn);
|
||||
osmux_handle_put(conn->osmux.in);
|
||||
}
|
||||
conn_osmux_release_cid(conn);
|
||||
osmux_xfrm_input_close_circuit(conn->osmux.in, conn->osmux.cid);
|
||||
conn->osmux.state = OSMUX_STATE_DISABLED;
|
||||
conn->osmux.cid = -1;
|
||||
osmux_handle_put(conn->osmux.in);
|
||||
}
|
||||
|
||||
/*! relase OSXMUX cid, that had been allocated to this connection.
|
||||
* \param[in] conn connection with OSMUX cid to release */
|
||||
void conn_osmux_release_cid(struct mgcp_conn_rtp *conn)
|
||||
void osmux_release_cid(struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
if (conn->osmux.cid_allocated)
|
||||
osmux_cid_pool_put(conn->osmux.cid);
|
||||
conn->osmux.cid = 0;
|
||||
conn->osmux.cid_allocated = false;
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
if (conn->osmux.state != OSMUX_STATE_ENABLED)
|
||||
return;
|
||||
|
||||
if (conn->osmux.allocated_cid >= 0)
|
||||
osmux_put_cid(conn->osmux.allocated_cid);
|
||||
conn->osmux.allocated_cid = -1;
|
||||
}
|
||||
|
||||
/*! allocate OSXMUX cid to connection.
|
||||
* \param[in] conn connection for which we allocate the OSMUX cid
|
||||
* \param[in] osmux_cid OSMUX cid to allocate. -1 Means take next available one.
|
||||
* \returns Allocated OSMUX cid, -1 on error (no free cids avail, or selected one is already taken).
|
||||
*/
|
||||
int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid)
|
||||
* \param[in] conn connection for which we allocate the OSMUX cid*/
|
||||
void osmux_allocate_cid(struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
if (osmux_cid != -1 && osmux_cid_pool_allocated((uint8_t) osmux_cid)) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
|
||||
"Osmux CID %d already allocated!\n",
|
||||
osmux_cid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (osmux_cid == -1) {
|
||||
osmux_cid = osmux_cid_pool_get_next();
|
||||
if (osmux_cid == -1) {
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_INFO,
|
||||
"no available Osmux CID to allocate!\n");
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
osmux_cid_pool_get(osmux_cid);
|
||||
|
||||
conn->osmux.cid = (uint8_t) osmux_cid;
|
||||
conn->osmux.cid_allocated = true;
|
||||
conn->type = MGCP_OSMUX_BSC;
|
||||
return osmux_cid;
|
||||
osmux_release_cid(conn);
|
||||
conn->osmux.allocated_cid = osmux_get_cid();
|
||||
}
|
||||
|
||||
/*! send RTP dummy packet to OSMUX connection port.
|
||||
@@ -576,9 +645,7 @@ int conn_osmux_allocate_cid(struct mgcp_conn_rtp *conn, int osmux_cid)
|
||||
* \returns bytes sent, -1 on error */
|
||||
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
|
||||
{
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
struct osmux_hdr *osmuxh;
|
||||
int buf_len;
|
||||
char buf[1 + sizeof(uint8_t)];
|
||||
struct in_addr addr_unset = {};
|
||||
|
||||
/*! The dummy packet will not be sent via the actual OSMUX connection,
|
||||
@@ -590,6 +657,9 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
|
||||
* endpoint may have already punched the hole in the firewall. This
|
||||
* approach is simple though. */
|
||||
|
||||
buf[0] = MGCP_DUMMY_LOAD;
|
||||
memcpy(&buf[1], &conn->osmux.cid, sizeof(conn->osmux.cid));
|
||||
|
||||
/* Wait until we have the connection information from MDCX */
|
||||
if (memcmp(&conn->end.addr, &addr_unset, sizeof(addr_unset)) == 0)
|
||||
return 0;
|
||||
@@ -597,20 +667,12 @@ int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
|
||||
if (endp_osmux_state_check(endp, conn, true) < 0)
|
||||
return 0;
|
||||
|
||||
buf_len = sizeof(struct osmux_hdr) + osmo_amr_bytes(AMR_FT_0);
|
||||
osmuxh = (struct osmux_hdr *) alloca(buf_len);
|
||||
memset(osmuxh, 0, buf_len);
|
||||
osmuxh->ft = OSMUX_FT_DUMMY;
|
||||
osmuxh->amr_ft = AMR_FT_0;
|
||||
osmuxh->circuit_id = conn->osmux.cid;
|
||||
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_DEBUG,
|
||||
"sending OSMUX dummy load to %s:%u CID %u\n",
|
||||
osmo_sockaddr_ntop(&conn->end.addr.u.sa, ipbuf),
|
||||
ntohs(conn->end.rtp_port), conn->osmux.cid);
|
||||
LOGP(DLMGCP, LOGL_DEBUG,
|
||||
"sending OSMUX dummy load to %s CID %u\n",
|
||||
inet_ntoa(conn->end.addr), conn->osmux.cid);
|
||||
|
||||
return mgcp_udp_send(osmux_fd.fd, &conn->end.addr,
|
||||
conn->end.rtp_port, (char*)osmuxh, buf_len);
|
||||
htons(endp->cfg->osmux_port), buf, sizeof(buf));
|
||||
}
|
||||
|
||||
/* bsc-nat allocates/releases the Osmux circuit ID. +7 to round up to 8 bit boundary. */
|
||||
@@ -618,7 +680,7 @@ static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1 + 7) / 8];
|
||||
|
||||
/*! count the number of taken OSMUX cids.
|
||||
* \returns number of OSMUX cids in use */
|
||||
int osmux_cid_pool_count_used(void)
|
||||
int osmux_used_cid(void)
|
||||
{
|
||||
int i, j, used = 0;
|
||||
|
||||
@@ -634,7 +696,7 @@ int osmux_cid_pool_count_used(void)
|
||||
|
||||
/*! take a free OSMUX cid.
|
||||
* \returns OSMUX cid */
|
||||
int osmux_cid_pool_get_next(void)
|
||||
int osmux_get_cid(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
@@ -654,24 +716,10 @@ int osmux_cid_pool_get_next(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! take a specific OSMUX cid.
|
||||
* \param[in] osmux_cid OSMUX cid */
|
||||
void osmux_cid_pool_get(uint8_t osmux_cid)
|
||||
{
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Allocating Osmux CID %u from pool\n", osmux_cid);
|
||||
osmux_cid_bitmap[osmux_cid / 8] |= (1 << (osmux_cid % 8));
|
||||
}
|
||||
|
||||
/*! put back a no longer used OSMUX cid.
|
||||
* \param[in] osmux_cid OSMUX cid */
|
||||
void osmux_cid_pool_put(uint8_t osmux_cid)
|
||||
void osmux_put_cid(uint8_t osmux_cid)
|
||||
{
|
||||
LOGP(DLMGCP, LOGL_DEBUG, "Osmux CID %u is back to the pool\n", osmux_cid);
|
||||
osmux_cid_bitmap[osmux_cid / 8] &= ~(1 << (osmux_cid % 8));
|
||||
}
|
||||
|
||||
/*! check if OSMUX cid is already taken */
|
||||
bool osmux_cid_pool_allocated(uint8_t osmux_cid)
|
||||
{
|
||||
return !!(osmux_cid_bitmap[osmux_cid / 8] & (1 << (osmux_cid % 8)));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,325 +0,0 @@
|
||||
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
|
||||
/* rate-counter implementation */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <errno.h>
|
||||
#include <osmocom/core/stats.h>
|
||||
#include <osmocom/core/stat_item.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_ratectr.h>
|
||||
|
||||
static const struct rate_ctr_desc mgcp_general_ctr_desc[] = {
|
||||
/* rx_msgs = rx_msgs_retransmitted + rx_msgs_handled + rx_msgs_unhandled + err_rx_msg_parse + err_rx_no_endpoint */
|
||||
[MGCP_GENERAL_RX_MSGS_TOTAL] = { "mgcp:rx_msgs", "total number of MGCP messages received." },
|
||||
[MGCP_GENERAL_RX_MSGS_RETRANSMITTED] = { "mgcp:rx_msgs_retransmitted", "number of received retransmissions." },
|
||||
[MGCP_GENERAL_RX_MSGS_HANDLED] = { "mgcp:rx_msgs_handled", "number of handled MGCP messages." },
|
||||
[MGCP_GENERAL_RX_MSGS_UNHANDLED] = { "mgcp:rx_msgs_unhandled", "number of unhandled MGCP messages." },
|
||||
[MGCP_GENERAL_RX_FAIL_MSG_PARSE] = { "mgcp:err_rx_msg_parse", "error parsing MGCP message." },
|
||||
[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT] =
|
||||
{ "mgcp:err_rx_no_endpoint", "can't find MGCP endpoint, probably we've used all allocated endpoints." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_general_ctr_group_desc = {
|
||||
.group_name_prefix = "mgcp",
|
||||
.group_description = "mgcp general statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_ctr = ARRAY_SIZE(mgcp_general_ctr_desc),
|
||||
.ctr_desc = mgcp_general_ctr_desc
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc mgcp_crcx_ctr_desc[] = {
|
||||
[MGCP_CRCX_SUCCESS] = { "crcx:success", "CRCX command processed successfully." },
|
||||
[MGCP_CRCX_FAIL_BAD_ACTION] = { "crcx:bad_action", "bad action in CRCX command." },
|
||||
[MGCP_CRCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in CRCX command." },
|
||||
[MGCP_CRCX_FAIL_MISSING_CALLID] = { "crcx:missing_callid", "missing CallId in CRCX command." },
|
||||
[MGCP_CRCX_FAIL_INVALID_MODE] = { "crcx:invalid_mode", "invalid connection mode in CRCX command." },
|
||||
[MGCP_CRCX_FAIL_LIMIT_EXCEEDED] = { "crcx:limit_exceeded", "limit of concurrent connections was reached." },
|
||||
[MGCP_CRCX_FAIL_UNKNOWN_CALLID] = { "crcx:unkown_callid", "unknown CallId in CRCX command." },
|
||||
[MGCP_CRCX_FAIL_ALLOC_CONN] = { "crcx:alloc_conn_fail", "connection allocation failure." },
|
||||
[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC] =
|
||||
{ "crcx:no_remote_conn_desc", "no opposite end specified for connection." },
|
||||
[MGCP_CRCX_FAIL_START_RTP] = { "crcx:start_rtp_failure", "failure to start RTP processing." },
|
||||
[MGCP_CRCX_FAIL_NO_OSMUX] = { "crcx:no_osmux", "no osmux offered by peer." },
|
||||
[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS] = { "crcx:conn_opt", "connection options invalid." },
|
||||
[MGCP_CRCX_FAIL_CODEC_NEGOTIATION] = { "crcx:codec_nego", "codec negotiation failure." },
|
||||
[MGCP_CRCX_FAIL_BIND_PORT] = { "crcx:bind_port", "port bind failure." },
|
||||
[MGCP_CRCX_FAIL_AVAIL] = { "crcx:unavailable", "endpoint unavailable." },
|
||||
[MGCP_CRCX_FAIL_CLAIM] = { "crcx:claim", "endpoint can not be claimed." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_crcx_ctr_group_desc = {
|
||||
.group_name_prefix = "crcx",
|
||||
.group_description = "crxc statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_ctr = ARRAY_SIZE(mgcp_crcx_ctr_desc),
|
||||
.ctr_desc = mgcp_crcx_ctr_desc
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc mgcp_mdcx_ctr_desc[] = {
|
||||
[MGCP_MDCX_SUCCESS] = { "mdcx:success", "MDCX command processed successfully." },
|
||||
[MGCP_MDCX_FAIL_WILDCARD] = { "mdcx:wildcard", "wildcard endpoint names in MDCX commands are unsupported." },
|
||||
[MGCP_MDCX_FAIL_NO_CONN] = { "mdcx:no_conn", "endpoint specified in MDCX command has no active connections." },
|
||||
[MGCP_MDCX_FAIL_INVALID_CALLID] = { "mdcx:callid", "invalid CallId specified in MDCX command." },
|
||||
[MGCP_MDCX_FAIL_INVALID_CONNID] = { "mdcx:connid", "invalid connection ID specified in MDCX command." },
|
||||
[MGCP_MDCX_FAIL_UNHANDLED_PARAM] = { "crcx:unhandled_param", "unhandled parameter in MDCX command." },
|
||||
[MGCP_MDCX_FAIL_NO_CONNID] = { "mdcx:no_connid", "no connection ID specified in MDCX command." },
|
||||
[MGCP_MDCX_FAIL_CONN_NOT_FOUND] =
|
||||
{ "mdcx:conn_not_found", "connection specified in MDCX command does not exist." },
|
||||
[MGCP_MDCX_FAIL_INVALID_MODE] = { "mdcx:invalid_mode", "invalid connection mode in MDCX command." },
|
||||
[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS] = { "mdcx:conn_opt", "connection options invalid." },
|
||||
[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC] =
|
||||
{ "mdcx:no_remote_conn_desc", "no opposite end specified for connection." },
|
||||
[MGCP_MDCX_FAIL_START_RTP] = { "mdcx:start_rtp_failure", "failure to start RTP processing." },
|
||||
[MGCP_MDCX_FAIL_AVAIL] = { "mdcx:unavailable", "endpoint unavailable." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_mdcx_ctr_group_desc = {
|
||||
.group_name_prefix = "mdcx",
|
||||
.group_description = "mdcx statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_ctr = ARRAY_SIZE(mgcp_mdcx_ctr_desc),
|
||||
.ctr_desc = mgcp_mdcx_ctr_desc
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc mgcp_dlcx_ctr_desc[] = {
|
||||
[MGCP_DLCX_SUCCESS] = { "dlcx:success", "DLCX command processed successfully." },
|
||||
[MGCP_DLCX_FAIL_NO_CONN] = { "dlcx:no_conn", "endpoint specified in DLCX command has no active connections." },
|
||||
[MGCP_DLCX_FAIL_INVALID_CALLID] =
|
||||
{ "dlcx:callid", "CallId specified in DLCX command mismatches endpoint's CallId ." },
|
||||
[MGCP_DLCX_FAIL_INVALID_CONNID] =
|
||||
{ "dlcx:connid", "connection ID specified in DLCX command does not exist on endpoint." },
|
||||
[MGCP_DLCX_FAIL_UNHANDLED_PARAM] = { "dlcx:unhandled_param", "unhandled parameter in DLCX command." },
|
||||
[MGCP_DLCX_FAIL_AVAIL] = { "dlcx:unavailable", "endpoint unavailable." },
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc mgcp_dlcx_ctr_group_desc = {
|
||||
.group_name_prefix = "dlcx",
|
||||
.group_description = "dlcx statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_ctr = ARRAY_SIZE(mgcp_dlcx_ctr_desc),
|
||||
.ctr_desc = mgcp_dlcx_ctr_desc
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc e1_rate_ctr_desc[] = {
|
||||
[E1_I460_TRAU_RX_FAIL_CTR] = { "e1:rx_fail", "Inbound I.460 TRAU failures." },
|
||||
[E1_I460_TRAU_TX_FAIL_CTR] = { "e1:tx_fail", "Outbound I.460 TRAU failures." },
|
||||
[E1_I460_TRAU_MUX_EMPTY_CTR] = { "e1:i460", "Outbound I.460 MUX queue empty." }
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc e1_rate_ctr_group_desc = {
|
||||
.group_name_prefix = "e1",
|
||||
.group_description = "e1 statistics",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_ctr = ARRAY_SIZE(e1_rate_ctr_desc),
|
||||
.ctr_desc = e1_rate_ctr_desc
|
||||
};
|
||||
|
||||
const static struct rate_ctr_group_desc all_rtp_conn_rate_ctr_group_desc = {
|
||||
.group_name_prefix = "all_rtp_conn",
|
||||
.group_description = "aggregated statistics for all rtp connections",
|
||||
.class_id = 1,
|
||||
.num_ctr = ARRAY_SIZE(all_rtp_conn_rate_ctr_desc),
|
||||
.ctr_desc = all_rtp_conn_rate_ctr_desc
|
||||
};
|
||||
|
||||
/*! allocate global rate counters
|
||||
* (called once at startup).
|
||||
* \param[in] cfg mgw configuration for which the rate counters are allocated.
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_ratectr_global_alloc(struct mgcp_config *cfg)
|
||||
{
|
||||
struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
|
||||
static atomic_uint general_rate_ctr_index = 0;
|
||||
char ctr_name[512];
|
||||
|
||||
if (ratectr->mgcp_general_ctr_group == NULL) {
|
||||
ratectr->mgcp_general_ctr_group =
|
||||
rate_ctr_group_alloc(cfg, &mgcp_general_ctr_group_desc, general_rate_ctr_index++);
|
||||
if (!ratectr->mgcp_general_ctr_group)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s:general", cfg->domain);
|
||||
rate_ctr_group_set_name(ratectr->mgcp_general_ctr_group, ctr_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! free global rate counters
|
||||
* (called once at process shutdown).
|
||||
* \param[in] cfg mgw configuration for which the rate counters are allocated. */
|
||||
void mgcp_ratectr_global_free(struct mgcp_config *cfg)
|
||||
{
|
||||
struct mgcp_ratectr_global *ratectr = &cfg->ratectr;
|
||||
|
||||
if (ratectr->mgcp_general_ctr_group) {
|
||||
rate_ctr_group_free(ratectr->mgcp_general_ctr_group);
|
||||
ratectr->mgcp_general_ctr_group = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*! allocate trunk specific rate counters
|
||||
* (called once on trunk initialization).
|
||||
* \param[in] trunk mgw trunk for which the rate counters are allocated.
|
||||
* \returns 0 on success, -EINVAL on failure */
|
||||
int mgcp_ratectr_trunk_alloc(struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
|
||||
static atomic_uint crcx_rate_ctr_index = 0;
|
||||
static atomic_uint mdcx_rate_ctr_index = 0;
|
||||
static atomic_uint dlcx_rate_ctr_index = 0;
|
||||
static atomic_uint all_rtp_conn_rate_ctr_index = 0;
|
||||
char ctr_name[256];
|
||||
|
||||
if (ratectr->mgcp_crcx_ctr_group == NULL) {
|
||||
ratectr->mgcp_crcx_ctr_group =
|
||||
rate_ctr_group_alloc(trunk, &mgcp_crcx_ctr_group_desc, crcx_rate_ctr_index++);
|
||||
if (!ratectr->mgcp_crcx_ctr_group)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:crcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->mgcp_crcx_ctr_group, ctr_name);
|
||||
}
|
||||
if (ratectr->mgcp_mdcx_ctr_group == NULL) {
|
||||
ratectr->mgcp_mdcx_ctr_group =
|
||||
rate_ctr_group_alloc(trunk, &mgcp_mdcx_ctr_group_desc, mdcx_rate_ctr_index++);
|
||||
if (!ratectr->mgcp_mdcx_ctr_group)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:mdcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->mgcp_mdcx_ctr_group, ctr_name);
|
||||
}
|
||||
if (ratectr->mgcp_dlcx_ctr_group == NULL) {
|
||||
ratectr->mgcp_dlcx_ctr_group =
|
||||
rate_ctr_group_alloc(trunk, &mgcp_dlcx_ctr_group_desc, dlcx_rate_ctr_index++);
|
||||
if (!ratectr->mgcp_dlcx_ctr_group)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:dlcx", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->mgcp_dlcx_ctr_group, ctr_name);
|
||||
}
|
||||
if (ratectr->all_rtp_conn_stats == NULL) {
|
||||
ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc,
|
||||
all_rtp_conn_rate_ctr_index++);
|
||||
if (!ratectr->all_rtp_conn_stats)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:rtp_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
|
||||
}
|
||||
|
||||
/* E1 specific */
|
||||
if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
|
||||
ratectr->e1_stats = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
|
||||
if (!ratectr->e1_stats)
|
||||
return -EINVAL;
|
||||
snprintf(ctr_name, sizeof(ctr_name), "%s-%u:e1", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
rate_ctr_group_set_name(ratectr->e1_stats, ctr_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! free trunk specific rate counters
|
||||
* (called once when trunk is freed).
|
||||
* \param[in] trunk mgw trunk on which the rate counters are allocated. */
|
||||
void mgcp_ratectr_trunk_free(struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_ratectr_trunk *ratectr = &trunk->ratectr;
|
||||
|
||||
if (ratectr->mgcp_crcx_ctr_group) {
|
||||
rate_ctr_group_free(ratectr->mgcp_crcx_ctr_group);
|
||||
ratectr->mgcp_crcx_ctr_group = NULL;
|
||||
}
|
||||
if (ratectr->mgcp_mdcx_ctr_group) {
|
||||
rate_ctr_group_free(ratectr->mgcp_mdcx_ctr_group);
|
||||
ratectr->mgcp_mdcx_ctr_group = NULL;
|
||||
}
|
||||
if (ratectr->mgcp_dlcx_ctr_group) {
|
||||
rate_ctr_group_free(ratectr->mgcp_dlcx_ctr_group);
|
||||
ratectr->mgcp_dlcx_ctr_group = NULL;
|
||||
}
|
||||
if (ratectr->all_rtp_conn_stats) {
|
||||
rate_ctr_group_free(ratectr->all_rtp_conn_stats);
|
||||
ratectr->all_rtp_conn_stats = NULL;
|
||||
}
|
||||
|
||||
/* E1 specific */
|
||||
if (ratectr->e1_stats) {
|
||||
rate_ctr_group_free(ratectr->e1_stats);
|
||||
ratectr->e1_stats = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct osmo_stat_item_desc trunk_stat_desc[] = {
|
||||
[TRUNK_STAT_ENDPOINTS_TOTAL] = { "endpoints:total",
|
||||
"Number of endpoints that exist on the trunk",
|
||||
"", 60, 0 },
|
||||
[TRUNK_STAT_ENDPOINTS_USED] = { "endpoints:used",
|
||||
"Number of endpoints in use",
|
||||
"", 60, 0 },
|
||||
};
|
||||
|
||||
const struct osmo_stat_item_group_desc trunk_statg_desc = {
|
||||
.group_name_prefix = "trunk",
|
||||
.group_description = "mgw trunk",
|
||||
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||
.num_items = ARRAY_SIZE(trunk_stat_desc),
|
||||
.item_desc = trunk_stat_desc,
|
||||
};
|
||||
|
||||
/*! allocate trunk specific stat items
|
||||
* (called once on trunk initialization).
|
||||
* \param[in] trunk for which the stat items are allocated.
|
||||
* \returns 0 on success, -EINVAL on failure. */
|
||||
int mgcp_stat_trunk_alloc(struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_stat_trunk *stats = &trunk->stats;
|
||||
static unsigned int common_stat_index = 0;
|
||||
char stat_name[256];
|
||||
|
||||
stats->common = osmo_stat_item_group_alloc(trunk, &trunk_statg_desc, common_stat_index);
|
||||
if (!stats->common)
|
||||
return -EINVAL;
|
||||
snprintf(stat_name, sizeof(stat_name), "%s-%u:common", mgcp_trunk_type_strs_str(trunk->trunk_type),
|
||||
trunk->trunk_nr);
|
||||
osmo_stat_item_group_set_name(stats->common, stat_name);
|
||||
common_stat_index++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! free trunk specific stat items
|
||||
* (called once when trunk is freed).
|
||||
* \param[in] trunk on which the stat items are allocated. */
|
||||
void mgcp_stat_trunk_free(struct mgcp_trunk *trunk)
|
||||
{
|
||||
struct mgcp_stat_trunk *stats = &trunk->stats;
|
||||
|
||||
if (stats->common) {
|
||||
osmo_stat_item_group_free(stats->common);
|
||||
stats->common = NULL;
|
||||
}
|
||||
}
|
||||
@@ -21,27 +21,17 @@
|
||||
*/
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/osmux.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/mgcp_msg.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_codec.h>
|
||||
#include <osmocom/mgcp/mgcp_sdp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Two structs to store intermediate parsing results. The function
|
||||
* mgcp_parse_sdp_data() is using the following two structs as temporary
|
||||
* storage for parsing the SDP codec information. */
|
||||
/* A struct to store intermediate parsing results. The function
|
||||
* mgcp_parse_sdp_data() is using it as temporary storage for parsing the SDP
|
||||
* codec information. */
|
||||
struct sdp_rtp_map {
|
||||
/* the type */
|
||||
int payload_type;
|
||||
@@ -53,11 +43,6 @@ struct sdp_rtp_map {
|
||||
int rate;
|
||||
int channels;
|
||||
};
|
||||
struct sdp_fmtp_param {
|
||||
int payload_type;
|
||||
struct mgcp_codec_param param;
|
||||
};
|
||||
|
||||
|
||||
/* Helper function to extrapolate missing codec parameters in a codec mao from
|
||||
* an already filled in payload_type, called from: mgcp_parse_sdp_data() */
|
||||
@@ -138,8 +123,7 @@ static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
|
||||
char *str;
|
||||
char *str_ptr;
|
||||
char *pt_str;
|
||||
char *pt_end;
|
||||
unsigned long int pt;
|
||||
unsigned int pt;
|
||||
unsigned int count = 0;
|
||||
unsigned int i;
|
||||
|
||||
@@ -164,14 +148,7 @@ static int pt_from_sdp(void *ctx, struct sdp_rtp_map *codecs,
|
||||
if (!pt_str)
|
||||
break;
|
||||
|
||||
errno = 0;
|
||||
pt = strtoul(pt_str, &pt_end, 0);
|
||||
if ((errno == ERANGE && pt == ULONG_MAX) || (errno && !pt) ||
|
||||
pt_str == pt_end)
|
||||
goto error;
|
||||
|
||||
if (pt >> 7) /* PT is 7 bit field, higher values not allowed */
|
||||
goto error;
|
||||
pt = atoi(pt_str);
|
||||
|
||||
/* Do not allow duplicate payload types */
|
||||
for (i = 0; i < count; i++)
|
||||
@@ -190,128 +167,6 @@ error:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Extract fmtp parameters from SDP, called from: mgcp_parse_sdp_data() */
|
||||
static int fmtp_from_sdp(void *ctx, struct sdp_fmtp_param *fmtp_param, char *sdp)
|
||||
{
|
||||
char *str;
|
||||
char *str_ptr;
|
||||
char *param_str;
|
||||
unsigned int pt;
|
||||
unsigned int count = 0;
|
||||
char delimiter;
|
||||
unsigned int amr_octet_aligned;
|
||||
|
||||
memset(fmtp_param, 0, sizeof(*fmtp_param));
|
||||
|
||||
str = talloc_zero_size(ctx, strlen(sdp) + 1);
|
||||
str_ptr = str;
|
||||
strcpy(str_ptr, sdp);
|
||||
|
||||
/* Check if the input string begins with an fmtp token */
|
||||
str_ptr = strstr(str_ptr, "fmtp:");
|
||||
if (!str_ptr)
|
||||
goto exit;
|
||||
str_ptr += 5;
|
||||
|
||||
/* Extract payload type */
|
||||
if (sscanf(str_ptr, "%u ", &pt) != 1)
|
||||
goto error;
|
||||
fmtp_param->payload_type = pt;
|
||||
|
||||
/* Advance pointer to the beginning of the parameter section and
|
||||
* tokenize string */
|
||||
str_ptr = strstr(str_ptr, " ");
|
||||
if (!str_ptr)
|
||||
goto error;
|
||||
str_ptr++;
|
||||
|
||||
param_str = strtok(str_ptr, " ");
|
||||
if (!param_str)
|
||||
goto exit;
|
||||
|
||||
while (1) {
|
||||
/* Make sure that we don't get trapped in an endless loop */
|
||||
if (count > 256)
|
||||
goto error;
|
||||
|
||||
/* Chop off delimiters ';' at the end */
|
||||
delimiter = str_ptr[strlen(str_ptr) - 1];
|
||||
if (delimiter == ';' || delimiter == ',')
|
||||
str_ptr[strlen(str_ptr) - 1] = '\0';
|
||||
|
||||
/* AMR octet aligned parameter */
|
||||
if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) {
|
||||
fmtp_param->param.amr_octet_aligned_present = true;
|
||||
fmtp_param->param.amr_octet_aligned = false;
|
||||
if (amr_octet_aligned == 1)
|
||||
fmtp_param->param.amr_octet_aligned = true;
|
||||
|
||||
}
|
||||
|
||||
param_str = strtok(NULL, " ");
|
||||
if (!param_str)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
|
||||
exit:
|
||||
talloc_free(str);
|
||||
return 0;
|
||||
error:
|
||||
talloc_free(str);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int audio_ip_from_sdp(struct osmo_sockaddr *dst_addr, char *sdp)
|
||||
{
|
||||
bool is_ipv6;
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
if (strncmp("c=IN IP", sdp, 7) != 0)
|
||||
return -1;
|
||||
sdp += 7;
|
||||
if (*sdp == '6')
|
||||
is_ipv6 = true;
|
||||
else if (*sdp == '4')
|
||||
is_ipv6 = false;
|
||||
else
|
||||
return -1;
|
||||
sdp++;
|
||||
if (*sdp != ' ')
|
||||
return -1;
|
||||
sdp++;
|
||||
if (is_ipv6) {
|
||||
/* 45 = INET6_ADDRSTRLEN -1 */
|
||||
if (sscanf(sdp, "%45s", ipbuf) != 1)
|
||||
return -1;
|
||||
if (inet_pton(AF_INET6, ipbuf, &dst_addr->u.sin6.sin6_addr) != 1)
|
||||
return -1;
|
||||
dst_addr->u.sa.sa_family = AF_INET6;
|
||||
} else {
|
||||
/* 15 = INET_ADDRSTRLEN -1 */
|
||||
if (sscanf(sdp, "%15s", ipbuf) != 1)
|
||||
return -1;
|
||||
if (inet_pton(AF_INET, ipbuf, &dst_addr->u.sin.sin_addr) != 1)
|
||||
return -1;
|
||||
dst_addr->u.sa.sa_family = AF_INET;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pick optional fmtp parameters by payload type, if there are no fmtp
|
||||
* parameters, a nullpointer is returned */
|
||||
static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < fmtp_params_len; i++) {
|
||||
if (fmtp_params[i].payload_type == pt)
|
||||
return &fmtp_params[i].param;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Analyze SDP input string.
|
||||
* \param[in] endp trunk endpoint.
|
||||
* \param[out] conn associated rtp connection.
|
||||
@@ -325,10 +180,6 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||
{
|
||||
struct sdp_rtp_map codecs[MGCP_MAX_CODECS];
|
||||
unsigned int codecs_used = 0;
|
||||
struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS];
|
||||
unsigned int fmtp_used = 0;
|
||||
struct mgcp_codec_param *codec_param;
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
char *line;
|
||||
unsigned int i;
|
||||
void *tmp_ctx = talloc_new(NULL);
|
||||
@@ -338,6 +189,7 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||
int ptime, ptime2 = 0;
|
||||
char audio_name[64];
|
||||
int port, rc;
|
||||
char ipv4[16];
|
||||
|
||||
OSMO_ASSERT(endp);
|
||||
OSMO_ASSERT(conn);
|
||||
@@ -355,31 +207,20 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||
/* skip these SDP attributes */
|
||||
break;
|
||||
case 'a':
|
||||
if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) {
|
||||
codecs_update(tmp_ctx, codecs, codecs_used, payload, audio_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
|
||||
if (sscanf(line, "a=rtpmap:%d %63s",
|
||||
&payload, audio_name) == 2) {
|
||||
codecs_update(tmp_ctx, codecs,
|
||||
codecs_used, payload, audio_name);
|
||||
} else
|
||||
if (sscanf
|
||||
(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) {
|
||||
if (ptime2 > 0 && ptime2 != ptime)
|
||||
rtp->packet_duration_ms = 0;
|
||||
else
|
||||
rtp->packet_duration_ms = ptime;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
|
||||
} else if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) {
|
||||
rtp->maximum_packet_time = ptime2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp("a=fmtp:", line, 6) == 0) {
|
||||
rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line);
|
||||
if (rc >= 0)
|
||||
fmtp_used++;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'm':
|
||||
rc = sscanf(line, "m=audio %d RTP/AVP", &port);
|
||||
@@ -394,18 +235,17 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||
codecs_used = rc;
|
||||
break;
|
||||
case 'c':
|
||||
if (audio_ip_from_sdp(&rtp->addr, line) < 0) {
|
||||
talloc_free(tmp_ctx);
|
||||
return -1;
|
||||
|
||||
if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
|
||||
inet_aton(ipv4, &rtp->addr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (endp)
|
||||
/* TODO: Check spec: We used the bare endpoint number before,
|
||||
* now we use the endpoint name as a whole? Is this allowed? */
|
||||
if (p->endp)
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Unhandled SDP option: '%c'/%d on %s\n",
|
||||
line[0], line[0], endp->name);
|
||||
"Unhandled SDP option: '%c'/%d on 0x%x\n",
|
||||
line[0], line[0],
|
||||
ENDPOINT_NUMBER(p->endp));
|
||||
else
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Unhandled SDP option: '%c'/%d\n",
|
||||
@@ -422,24 +262,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
|
||||
|
||||
/* Store parsed codec information */
|
||||
for (i = 0; i < codecs_used; i++) {
|
||||
codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used);
|
||||
rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param);
|
||||
rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line);
|
||||
if (rc < 0)
|
||||
LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n");
|
||||
LOGP(DLMGCP, LOGL_NOTICE, "endpoint:0x%x, failed to add codec\n", ENDPOINT_NUMBER(p->endp));
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE,
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:",
|
||||
ntohs(rtp->rtp_port), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf),
|
||||
ntohs(rtp->rtp_port), inet_ntoa(rtp->addr),
|
||||
rtp->packet_duration_ms);
|
||||
if (codecs_used == 0)
|
||||
LOGPC(DLMGCP, LOGL_NOTICE, "none");
|
||||
for (i = 0; i < codecs_used; i++) {
|
||||
LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s",
|
||||
rtp->codecs[i].payload_type,
|
||||
strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown");
|
||||
rtp->codecs[i].subtype_name ? rtp-> codecs[i].subtype_name : "unknown");
|
||||
LOGPC(DLMGCP, LOGL_NOTICE, " ");
|
||||
}
|
||||
LOGPC(DLMGCP, LOGL_NOTICE, "\n");
|
||||
@@ -465,12 +304,15 @@ static int add_rtpmap(struct msgb *sdp, int payload_type, const char *audio_name
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add audio strings to sdp payload */
|
||||
/* Add audio string to sdp payload */
|
||||
static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_types_len, int local_port)
|
||||
{
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
if (payload_types_len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
rc = msgb_printf(sdp, "m=audio %d RTP/AVP", local_port);
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
@@ -488,66 +330,6 @@ static int add_audio(struct msgb *sdp, int *payload_types, unsigned int payload_
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add fmtp strings to sdp payload */
|
||||
static int add_fmtp(struct msgb *sdp, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len,
|
||||
const char *fmtp_extra)
|
||||
{
|
||||
unsigned int i;
|
||||
int rc;
|
||||
int fmtp_extra_pt = -1;
|
||||
char *fmtp_extra_pars = "";
|
||||
|
||||
/* When no fmtp parameters ara available but an fmtp extra string
|
||||
* is configured, just add the fmtp extra string */
|
||||
if (fmtp_params_len == 0 && fmtp_extra) {
|
||||
return msgb_printf(sdp, "%s\r\n", fmtp_extra);
|
||||
}
|
||||
|
||||
/* When there is fmtp extra configured we dissect it in order to drop
|
||||
* in the configured extra parameters at the right place when
|
||||
* generating the fmtp strings. */
|
||||
if (fmtp_extra) {
|
||||
if (sscanf(fmtp_extra, "a=fmtp:%d ", &fmtp_extra_pt) != 1)
|
||||
fmtp_extra_pt = -1;
|
||||
|
||||
fmtp_extra_pars = strstr(fmtp_extra, " ");
|
||||
|
||||
if (!fmtp_extra_pars)
|
||||
fmtp_extra_pars = "";
|
||||
else
|
||||
fmtp_extra_pars++;
|
||||
}
|
||||
|
||||
for (i = 0; i < fmtp_params_len; i++) {
|
||||
rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type);
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Add amr octet align parameter */
|
||||
if (fmtp_params[i].param.amr_octet_aligned_present) {
|
||||
if (fmtp_params[i].param.amr_octet_aligned)
|
||||
rc = msgb_printf(sdp, " octet-align=1");
|
||||
else
|
||||
rc = msgb_printf(sdp, " octet-align=0");
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Append extra parameters from fmtp extra */
|
||||
if (fmtp_params[i].payload_type == fmtp_extra_pt) {
|
||||
rc = msgb_printf(sdp, " %s", fmtp_extra_pars);
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msgb_printf(sdp, "\r\n");
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Generate SDP response string.
|
||||
* \param[in] endp trunk endpoint.
|
||||
* \param[in] conn associated rtp connection.
|
||||
@@ -558,17 +340,11 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
|
||||
const char *addr)
|
||||
{
|
||||
const struct mgcp_rtp_codec *codec;
|
||||
const char *fmtp_extra;
|
||||
const char *audio_name;
|
||||
int payload_type;
|
||||
struct sdp_fmtp_param fmtp_param;
|
||||
int rc;
|
||||
int payload_types[1];
|
||||
int local_port;
|
||||
struct sdp_fmtp_param fmtp_params[1];
|
||||
unsigned int fmtp_params_len = 0;
|
||||
bool addr_is_v6;
|
||||
|
||||
OSMO_ASSERT(endp);
|
||||
OSMO_ASSERT(conn);
|
||||
@@ -576,23 +352,17 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||
OSMO_ASSERT(addr);
|
||||
|
||||
/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
|
||||
endp->trunk->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
|
||||
&codec, &fmtp_extra,
|
||||
endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
|
||||
&payload_type, &audio_name,
|
||||
&fmtp_extra,
|
||||
(struct mgcp_conn_rtp *)conn);
|
||||
|
||||
audio_name = codec->audio_name;
|
||||
payload_type = codec->payload_type;
|
||||
|
||||
addr_is_v6 = osmo_ip_str_type(addr) == AF_INET6;
|
||||
|
||||
rc = msgb_printf(sdp,
|
||||
"v=0\r\n"
|
||||
"o=- %s 23 IN IP%c %s\r\n"
|
||||
"o=- %s 23 IN IP4 %s\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP%c %s\r\n"
|
||||
"t=0 0\r\n", conn->conn->id,
|
||||
addr_is_v6 ? '6' : '4', addr,
|
||||
addr_is_v6 ? '6' : '4', addr);
|
||||
"c=IN IP4 %s\r\n"
|
||||
"t=0 0\r\n", conn->conn->id, addr, addr);
|
||||
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
@@ -600,31 +370,24 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||
if (payload_type >= 0) {
|
||||
|
||||
payload_types[0] = payload_type;
|
||||
if (mgcp_conn_rtp_is_osmux(conn))
|
||||
local_port = endp->trunk->cfg->osmux_port;
|
||||
else
|
||||
local_port = conn->end.local_port;
|
||||
rc = add_audio(sdp, payload_types, 1, local_port);
|
||||
rc = add_audio(sdp, payload_types, 1, conn->end.local_port);
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
|
||||
if (endp->trunk->audio_send_name) {
|
||||
if (endp->tcfg->audio_send_name) {
|
||||
rc = add_rtpmap(sdp, payload_type, audio_name);
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
}
|
||||
|
||||
if (codec->param_present) {
|
||||
fmtp_param.payload_type = payload_type;
|
||||
fmtp_param.param = codec->param;
|
||||
fmtp_params[0] = fmtp_param;
|
||||
fmtp_params_len = 1;
|
||||
if (fmtp_extra) {
|
||||
rc = msgb_printf(sdp, "%s\r\n", fmtp_extra);
|
||||
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
}
|
||||
rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra);
|
||||
if (rc < 0)
|
||||
goto buffer_too_small;
|
||||
}
|
||||
if (conn->end.packet_duration_ms > 0 && endp->trunk->audio_send_ptime) {
|
||||
if (conn->end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) {
|
||||
rc = msgb_printf(sdp, "a=ptime:%u\r\n",
|
||||
conn->end.packet_duration_ms);
|
||||
if (rc < 0)
|
||||
@@ -634,6 +397,6 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
|
||||
return 0;
|
||||
|
||||
buffer_too_small:
|
||||
LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
|
||||
LOGP(DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -22,24 +22,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_conn.h>
|
||||
#include <osmocom/mgcp/mgcp_stat.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(no_sanitize)
|
||||
__attribute__((no_sanitize("undefined")))
|
||||
#endif
|
||||
#endif
|
||||
void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
|
||||
{
|
||||
struct mgcp_rtp_state *state = &conn->state;
|
||||
struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
|
||||
struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
|
||||
|
||||
*expected = state->stats.cycles + state->stats.max_seq;
|
||||
*expected = *expected - state->stats.base_seq + 1;
|
||||
@@ -80,10 +72,10 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
|
||||
int ploss;
|
||||
int nchars;
|
||||
|
||||
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->rate_ctr_group, RTP_OCTETS_RX_CTR);
|
||||
struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
|
||||
struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
|
||||
struct rate_ctr *packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
|
||||
struct rate_ctr *octets_rx = &conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR];
|
||||
struct rate_ctr *packets_tx = &conn->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR];
|
||||
struct rate_ctr *octets_tx = &conn->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR];
|
||||
|
||||
calc_loss(conn, &expected, &ploss);
|
||||
jitter = calc_jitter(&conn->state);
|
||||
@@ -99,7 +91,7 @@ static void mgcp_format_stats_rtp(char *str, size_t str_len,
|
||||
str += nchars;
|
||||
str_len -= nchars;
|
||||
|
||||
if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
|
||||
if (conn->conn->endp->cfg->osmux != OSMUX_USAGE_OFF) {
|
||||
/* Error Counter */
|
||||
nchars = snprintf(str, str_len,
|
||||
"\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/* Trunk handling */
|
||||
|
||||
/*
|
||||
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009-2012 by On-Waves
|
||||
* (C) 2017-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_e1.h>
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/core/stat_item.h>
|
||||
|
||||
const struct value_string mgcp_trunk_type_strs[] = {
|
||||
{ MGCP_TRUNK_VIRTUAL, "virtual" },
|
||||
{ MGCP_TRUNK_E1, "e1" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Free trunk, this function is automatically called by talloc_free when the trunk is freed. It does not free the
|
||||
* endpoints on the trunk, this must be done separately before freeing the trunk. */
|
||||
static int trunk_free_talloc_destructor(struct mgcp_trunk *trunk)
|
||||
{
|
||||
llist_del(&trunk->entry);
|
||||
mgcp_ratectr_trunk_free(trunk);
|
||||
mgcp_stat_trunk_free(trunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! allocate trunk and add it to the trunk list.
|
||||
* (called once at startup by VTY).
|
||||
* \param[in] cfg mgcp configuration.
|
||||
* \param[in] ttype trunk type.
|
||||
* \param[in] nr trunk number.
|
||||
* \returns pointer to allocated trunk, NULL on failure. */
|
||||
struct mgcp_trunk *mgcp_trunk_alloc(struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
|
||||
{
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
trunk = talloc_zero(cfg, struct mgcp_trunk);
|
||||
if (!trunk) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "Failed to allocate.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
trunk->cfg = cfg;
|
||||
trunk->trunk_type = ttype;
|
||||
trunk->trunk_nr = nr;
|
||||
|
||||
trunk->audio_send_ptime = 1;
|
||||
trunk->audio_send_name = 1;
|
||||
trunk->v.vty_number_endpoints = 512;
|
||||
trunk->omit_rtcp = 0;
|
||||
|
||||
mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
|
||||
|
||||
llist_add_tail(&trunk->entry, &cfg->trunks);
|
||||
|
||||
mgcp_ratectr_trunk_alloc(trunk);
|
||||
mgcp_stat_trunk_alloc(trunk);
|
||||
talloc_set_destructor(trunk, trunk_free_talloc_destructor);
|
||||
|
||||
return trunk;
|
||||
}
|
||||
|
||||
/*! allocate endpoints and set default values
|
||||
* (called once at startup by VTY).
|
||||
* \param[in] trunk trunk configuration.
|
||||
* \returns 0 on success, -1 on failure. */
|
||||
int mgcp_trunk_alloc_endpts(struct mgcp_trunk *trunk)
|
||||
{
|
||||
int i;
|
||||
struct mgcp_endpoint *endp;
|
||||
unsigned int number_endpoints;
|
||||
unsigned int first_endpoint_nr;
|
||||
|
||||
/* This function is called once on startup by the VTY to allocate the
|
||||
* endpoints. The number of endpoints must not change througout the
|
||||
* runtime of the MGW */
|
||||
OSMO_ASSERT(trunk->number_endpoints == 0);
|
||||
OSMO_ASSERT(trunk->endpoints == NULL);
|
||||
|
||||
switch (trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
/* Due to historical reasons the endpoints on the virtual
|
||||
* trunk start counting at 1. */
|
||||
first_endpoint_nr = 1;
|
||||
number_endpoints = trunk->v.vty_number_endpoints;
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
/* The first timeslot on an E1 line is reserved for framing
|
||||
* and alignment and can not be used for audio transport */
|
||||
first_endpoint_nr = 1 * MGCP_ENDP_E1_SUBSLOTS;
|
||||
number_endpoints = (NUM_E1_TS-1) * MGCP_ENDP_E1_SUBSLOTS;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
/* Make sure the amount of requested endpoints does not execeed
|
||||
* sane limits. The VTY already limits the possible amount,
|
||||
* however miss-initialization of the struct or memory corruption
|
||||
* could still lead to an excessive allocation of endpoints, so
|
||||
* better stop early if that is the case. */
|
||||
OSMO_ASSERT(number_endpoints < 65534);
|
||||
|
||||
/* allocate pointer array for the endpoints */
|
||||
trunk->endpoints = talloc_zero_array(trunk, struct mgcp_endpoint*,
|
||||
number_endpoints);
|
||||
if (!trunk->endpoints)
|
||||
return -1;
|
||||
|
||||
/* create endpoints */
|
||||
for (i = 0; i < number_endpoints; i++) {
|
||||
endp = mgcp_endp_alloc(trunk, i + first_endpoint_nr);
|
||||
if (!endp) {
|
||||
talloc_free(trunk->endpoints);
|
||||
return -1;
|
||||
}
|
||||
trunk->endpoints[i] = endp;
|
||||
}
|
||||
|
||||
/* make the endpoints we just created available to the MGW code */
|
||||
trunk->number_endpoints = number_endpoints;
|
||||
osmo_stat_item_set(osmo_stat_item_group_get_item(trunk->stats.common, TRUNK_STAT_ENDPOINTS_TOTAL),
|
||||
trunk->number_endpoints);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Equip trunk with endpoints and resources
|
||||
* (called once at startup by VTY).
|
||||
* \param[in] trunk trunk configuration.
|
||||
* \returns 0 on success, -1 on failure. */
|
||||
int mgcp_trunk_equip(struct mgcp_trunk *trunk)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Allocate endpoints */
|
||||
if(mgcp_trunk_alloc_endpts(trunk) != 0)
|
||||
return -1;
|
||||
|
||||
/* Allocate resources */
|
||||
switch (trunk->trunk_type) {
|
||||
case MGCP_TRUNK_VIRTUAL:
|
||||
/* No additional initaliziation required here, virtual
|
||||
* endpoints will open/close network sockets themselves
|
||||
* on demand. */
|
||||
break;
|
||||
case MGCP_TRUNK_E1:
|
||||
/* The TS initalization happens once on startup for all
|
||||
* timeslots. This only affects the i460 multiplexer. Until
|
||||
* now no E1 resources are claimed yet. This happens on demand
|
||||
* when the related endpoint is actually used */
|
||||
memset(trunk->e1.i460_ts, 0, sizeof(trunk->e1.i460_ts));
|
||||
for (i = 0; i < (NUM_E1_TS-1); i++)
|
||||
osmo_i460_ts_init(&trunk->e1.i460_ts[i]);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! get trunk configuration by trunk number (index).
|
||||
* \param[in] cfg mgcp configuration.
|
||||
* \param[in] ttype trunk type.
|
||||
* \param[in] nr trunk number.
|
||||
* \returns pointer to trunk configuration, NULL on error. */
|
||||
struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_trunk_type ttype, unsigned int nr)
|
||||
{
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
llist_for_each_entry(trunk, &cfg->trunks, entry) {
|
||||
if (trunk->trunk_nr == nr && trunk->trunk_type == ttype)
|
||||
return trunk;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Made public for unit-testing, do not use from outside this file */
|
||||
int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname)
|
||||
{
|
||||
unsigned long trunk_nr_temp;
|
||||
size_t prefix_len;
|
||||
char *str_trunk_nr_end;
|
||||
|
||||
prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_E1_TRUNK) - 1;
|
||||
if (strncmp(epname, MGCP_ENDPOINT_PREFIX_E1_TRUNK, prefix_len) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
errno = 0;
|
||||
trunk_nr_temp = strtoul(epname + prefix_len, &str_trunk_nr_end, 10);
|
||||
if (errno == ERANGE || trunk_nr_temp > 64
|
||||
|| epname + prefix_len == str_trunk_nr_end
|
||||
|| str_trunk_nr_end[0] != '/')
|
||||
return -EINVAL;
|
||||
else {
|
||||
*trunk_nr = (unsigned int)trunk_nr_temp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the domain name, which is supplied with the endpoint name
|
||||
* matches the configuration. */
|
||||
static int check_domain_name(const char *epname, const struct mgcp_config *cfg)
|
||||
{
|
||||
char *domain_to_check;
|
||||
|
||||
domain_to_check = strstr(epname, "@");
|
||||
if (!domain_to_check) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "missing domain name in endpoint name \"%s\", expecting \"%s\"\n",
|
||||
epname, cfg->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Accept any domain if configured as "*" */
|
||||
if (!strcmp(cfg->domain, "*"))
|
||||
return 0;
|
||||
|
||||
if (strcmp(domain_to_check+1, cfg->domain) != 0) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "wrong domain name in endpoint name \"%s\", expecting \"%s\"\n",
|
||||
epname, cfg->domain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Find a trunk by the trunk prefix in the endpoint name.
|
||||
* \param[in] epname endpoint name with trunk prefix to look up.
|
||||
* \param[in] cfg that contains the trunks where the endpoint is located.
|
||||
* \returns trunk or NULL if trunk was not found. */
|
||||
struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname)
|
||||
{
|
||||
size_t prefix_len;
|
||||
char epname_lc[MGCP_ENDPOINT_MAXLEN];
|
||||
unsigned int trunk_nr;
|
||||
int rc;
|
||||
|
||||
osmo_str_tolower_buf(epname_lc, sizeof(epname_lc), epname);
|
||||
epname = epname_lc;
|
||||
|
||||
/* All endpoint names require a domain as suffix */
|
||||
if (check_domain_name(epname, cfg))
|
||||
return NULL;
|
||||
|
||||
prefix_len = sizeof(MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK) - 1;
|
||||
if (strncmp(epname, MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK, prefix_len) == 0) {
|
||||
return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
}
|
||||
|
||||
rc = e1_trunk_nr_from_epname(&trunk_nr, epname);
|
||||
if (rc == 0)
|
||||
return mgcp_trunk_by_num(cfg, MGCP_TRUNK_E1, trunk_nr);
|
||||
|
||||
/* Earlier versions of osmo-mgw were accepting endpoint names
|
||||
* without trunk prefix. This is normally not allowed, each MGCP
|
||||
* request should supply an endpoint name with trunk prefix.
|
||||
* However in order to stay compatible with old versions of
|
||||
* osmo-bsc and osmo-msc we still accept endpoint names without
|
||||
* trunk prefix and just assume that the virtual trunk should
|
||||
* be selected. There is even a TTCN3 test for this, see also:
|
||||
* MGCP_Test.TC_crcx_noprefix */
|
||||
if ((epname[0] >= '0' && epname[0] <= '9') || (epname[0] >= 'a' && epname[0] <= 'f')) {
|
||||
LOGP(DLMGCP, LOGL_ERROR, "missing trunk prefix in endpoint name \"%s\", assuming trunk \"%s\"!\n", epname,
|
||||
MGCP_ENDPOINT_PREFIX_VIRTUAL_TRUNK);
|
||||
return mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
|
||||
}
|
||||
|
||||
LOGP(DLMGCP, LOGL_ERROR, "unable to find trunk for endpoint name \"%s\"!\n", epname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Find a trunk (E1) by its associated E1 line number.
|
||||
* \param[in] num e1 line number.
|
||||
* \returns trunk or NULL if trunk was not found. */
|
||||
struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num)
|
||||
{
|
||||
/*! When used on trunks other than E1, the result will always be NULL. */
|
||||
struct mgcp_trunk *trunk;
|
||||
|
||||
llist_for_each_entry(trunk, &cfg->trunks, entry) {
|
||||
if (trunk->trunk_type == MGCP_TRUNK_E1 && trunk->e1.vty_line_nr == num)
|
||||
return trunk;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,7 @@ AM_CFLAGS = \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOTRAU_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -29,8 +26,5 @@ osmo_mgw_LDADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -30,18 +30,14 @@
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/abis/e1_input.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <osmocom/mgcp/mgcp.h>
|
||||
#include <osmocom/mgcp/mgcp_protocol.h>
|
||||
#include <osmocom/mgcp/mgcp_internal.h>
|
||||
#include <osmocom/mgcp/vty.h>
|
||||
#include <osmocom/mgcp/debug.h>
|
||||
#include <osmocom/mgcp/mgcp_endp.h>
|
||||
#include <osmocom/mgcp/mgcp_trunk.h>
|
||||
#include <osmocom/mgcp/mgcp_ctrl.h>
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
@@ -52,32 +48,22 @@
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/ports.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/vty/cpu_sched_vty.h>
|
||||
|
||||
#include <osmocom/abis/abis.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
/* can be changed once libosmocore 1.4.0 is released */
|
||||
#ifndef OSMO_CTRL_PORT_MGW
|
||||
#define OSMO_CTRL_PORT_MGW 4267
|
||||
#endif
|
||||
|
||||
/* FIXME: Make use of the rtp proxy code */
|
||||
|
||||
static struct mgcp_config *cfg;
|
||||
static struct mgcp_trunk *reset_trunk;
|
||||
static struct mgcp_trunk_config *reset_trunk;
|
||||
static int reset_endpoints = 0;
|
||||
static int daemonize = 0;
|
||||
|
||||
@@ -93,60 +79,28 @@ const char *osmomgw_copyright =
|
||||
static char *config_file = "osmo-mgw.cfg";
|
||||
|
||||
/* used by msgb and mgcp */
|
||||
void *tall_mgw_ctx = NULL;
|
||||
void *tall_bsc_ctx = NULL;
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
printf("Some useful options:\n");
|
||||
printf("Some useful help...\n");
|
||||
printf(" -h --help is printing this text.\n");
|
||||
printf(" -c --config-file filename The config file to use.\n");
|
||||
printf(" -s --disable-color\n");
|
||||
printf(" -D --daemonize Fork the process into a background daemon\n");
|
||||
printf(" -V --version Print the version number\n");
|
||||
|
||||
printf("\nVTY reference generation:\n");
|
||||
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
|
||||
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
|
||||
}
|
||||
|
||||
static void handle_long_options(const char *prog_name, const int long_option)
|
||||
{
|
||||
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
|
||||
|
||||
switch (long_option) {
|
||||
case 1:
|
||||
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
|
||||
if (vty_ref_mode < 0) {
|
||||
fprintf(stderr, "%s: Unknown VTY reference generation "
|
||||
"mode '%s'\n", prog_name, optarg);
|
||||
exit(2);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
|
||||
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
|
||||
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
|
||||
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static int long_option = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"config-file", 1, 0, 'c'},
|
||||
{"daemonize", 0, 0, 'D'},
|
||||
{"version", 0, 0, 'V'},
|
||||
{"disable-color", 0, 0, 's'},
|
||||
{"vty-ref-mode", 1, &long_option, 1},
|
||||
{"vty-ref-xml", 0, &long_option, 2},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -160,11 +114,8 @@ static void handle_options(int argc, char **argv)
|
||||
print_help();
|
||||
exit(0);
|
||||
break;
|
||||
case 0:
|
||||
handle_long_options(argv[0], long_option);
|
||||
break;
|
||||
case 'c':
|
||||
config_file = talloc_strdup(tall_mgw_ctx, optarg);
|
||||
config_file = talloc_strdup(tall_bsc_ctx, optarg);
|
||||
break;
|
||||
case 's':
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
@@ -181,28 +132,24 @@ static void handle_options(int argc, char **argv)
|
||||
break;
|
||||
};
|
||||
}
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback function to be called when the RSIP ("Reset in Progress") mgcp
|
||||
* command is received */
|
||||
static int mgcp_rsip_cb(struct mgcp_trunk *trunk)
|
||||
static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg)
|
||||
{
|
||||
/* Set flag so that, when read_call_agent() is called next time
|
||||
* the reset can progress */
|
||||
reset_endpoints = 1;
|
||||
|
||||
reset_trunk = trunk;
|
||||
reset_trunk = tcfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_call_agent(struct osmo_fd *fd, unsigned int what)
|
||||
{
|
||||
struct osmo_sockaddr addr;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
struct msgb *msg;
|
||||
struct msgb *resp;
|
||||
@@ -228,14 +175,14 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
|
||||
msgb_reset(msg);
|
||||
|
||||
if (resp) {
|
||||
sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, &addr.u.sa, sizeof(addr));
|
||||
sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
msgb_free(resp);
|
||||
}
|
||||
|
||||
/* reset endpoints */
|
||||
if (reset_endpoints) {
|
||||
LOGP(DLMGCP, LOGL_NOTICE,
|
||||
"Asked to reset endpoints: %u/%d\n",
|
||||
"Asked to reset endpoints: %d/%d\n",
|
||||
reset_trunk->trunk_nr, reset_trunk->trunk_type);
|
||||
|
||||
/* reset flag */
|
||||
@@ -243,8 +190,8 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
|
||||
|
||||
/* Walk over all endpoints and trigger a release, this will release all
|
||||
* endpoints, possible open connections are forcefully dropped */
|
||||
for (i = 0; i < reset_trunk->number_endpoints; ++i)
|
||||
mgcp_endp_release(reset_trunk->endpoints[i]);
|
||||
for (i = 1; i < reset_trunk->number_endpoints; ++i)
|
||||
mgcp_endp_release(&reset_trunk->endpoints[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -296,13 +243,13 @@ static const struct log_info_cat log_categories[] = {
|
||||
.description = "RTP stream handling",
|
||||
.color = "\033[1;30m",
|
||||
.enabled = 1,.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DE1] = {
|
||||
.name = "DE1",
|
||||
.description = "E1 line handling",
|
||||
},
|
||||
[DIUUP] = {
|
||||
.name = "DIUUP",
|
||||
.description = "IuUP within RTP stream handling",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,.loglevel = LOGL_NOTICE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const struct log_info log_info = {
|
||||
@@ -315,66 +262,52 @@ int main(int argc, char **argv)
|
||||
unsigned int flags;
|
||||
int rc;
|
||||
|
||||
tall_mgw_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
|
||||
vty_info.tall_ctx = tall_mgw_ctx;
|
||||
tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
|
||||
vty_info.tall_ctx = tall_bsc_ctx;
|
||||
|
||||
msgb_talloc_ctx_init(tall_mgw_ctx, 0);
|
||||
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
|
||||
|
||||
osmo_init_ignore_signals();
|
||||
osmo_init_logging2(tall_mgw_ctx, &log_info);
|
||||
libosmo_abis_init(tall_mgw_ctx);
|
||||
osmo_init_logging2(tall_bsc_ctx, &log_info);
|
||||
|
||||
cfg = mgcp_config_alloc();
|
||||
if (!cfg)
|
||||
return -1;
|
||||
|
||||
vty_info.copyright = osmomgw_copyright;
|
||||
vty_info.usr_attr_desc[MGW_CMD_ATTR_NEWCONN] = \
|
||||
"This command applies when a new connection is created";
|
||||
vty_info.usr_attr_letters[MGW_CMD_ATTR_NEWCONN] = 'n';
|
||||
|
||||
vty_init(&vty_info);
|
||||
logging_vty_add_cmds();
|
||||
logging_vty_add_cmds(NULL);
|
||||
osmo_talloc_vty_add_cmds();
|
||||
osmo_stats_vty_add_cmds();
|
||||
osmo_stats_vty_add_cmds(&log_info);
|
||||
mgcp_vty_init();
|
||||
ctrl_vty_init(cfg);
|
||||
e1inp_vty_init();
|
||||
osmo_cpu_sched_vty_init(tall_mgw_ctx);
|
||||
|
||||
handle_options(argc, argv);
|
||||
|
||||
rate_ctr_init(tall_mgw_ctx);
|
||||
osmo_stats_init(tall_mgw_ctx);
|
||||
rate_ctr_init(tall_bsc_ctx);
|
||||
osmo_stats_init(tall_bsc_ctx);
|
||||
|
||||
rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* start telnet after reading config for vty_get_bind_addr() */
|
||||
rc = telnet_init_dynif(tall_mgw_ctx, NULL,
|
||||
rc = telnet_init_dynif(tall_bsc_ctx, NULL,
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
cfg->ctrl = mgw_ctrl_interface_setup(cfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
|
||||
if (!cfg->ctrl) {
|
||||
fprintf(stderr, "Failed to init the control interface on %s:%u. Exiting\n",
|
||||
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_MGW);
|
||||
}
|
||||
|
||||
/* Set the reset callback function. This functions is called when the
|
||||
* mgcp-command "RSIP" (Reset in Progress) is received */
|
||||
cfg->reset_cb = mgcp_rsip_cb;
|
||||
|
||||
/* we need to bind a socket */
|
||||
flags = OSMO_SOCK_F_BIND;
|
||||
if (strlen(cfg->call_agent_addr))
|
||||
if (cfg->call_agent_addr)
|
||||
flags |= OSMO_SOCK_F_CONNECT;
|
||||
|
||||
rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||
rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
||||
cfg->source_addr, cfg->source_port,
|
||||
cfg->call_agent_addr, strlen(cfg->call_agent_addr) ? 2727 : 0, flags);
|
||||
cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
|
||||
if (rc < 0) {
|
||||
perror("Gateway failed to bind");
|
||||
return -1;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
SUBDIRS = \
|
||||
mgcp_client \
|
||||
mgcp \
|
||||
iuup \
|
||||
$(NULL)
|
||||
|
||||
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
|
||||
|
||||
45
tests/iuup/Makefile.am
Normal file
45
tests/iuup/Makefile.am
Normal file
@@ -0,0 +1,45 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
iuup_test.ok \
|
||||
iuup_test.err \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
iuup_test \
|
||||
$(NULL)
|
||||
|
||||
iuup_test_SOURCES = \
|
||||
iuup_test.c \
|
||||
$(NULL)
|
||||
|
||||
iuup_test_LDADD = \
|
||||
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBRARY_DL) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
-lm \
|
||||
$(NULL)
|
||||
|
||||
update_exp:
|
||||
$(builddir)/iuup_test >$(srcdir)/iuup_test.ok 2>$(srcdir)/iuup_test.err
|
||||
157
tests/iuup/iuup_test.c
Normal file
157
tests/iuup/iuup_test.c
Normal file
@@ -0,0 +1,157 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/mgcp/iuup_cn_node.h>
|
||||
#include <osmocom/mgcp/iuup_protocol.h>
|
||||
|
||||
void *ctx = NULL;
|
||||
|
||||
static const char *dump(struct msgb *msg)
|
||||
{
|
||||
return osmo_hexdump_nospc(msg->data, msg->len);
|
||||
}
|
||||
|
||||
struct msgb *msgb_from_hex(const char *label, const char *hex)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(4096 + OSMO_IUUP_HEADROOM,
|
||||
OSMO_IUUP_HEADROOM, label);
|
||||
unsigned char *rc;
|
||||
msg->l2h = msg->data;
|
||||
rc = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
|
||||
OSMO_ASSERT(rc == msg->l2h);
|
||||
return msg;
|
||||
}
|
||||
|
||||
const char *expect_rx_payload = NULL;
|
||||
int rx_payload(struct msgb *msg, void *node_priv)
|
||||
{
|
||||
printf("rx_payload() invoked by iuup_cn!\n");
|
||||
printf(" [IuUP] -RTP->\n");
|
||||
printf("%s\n", dump(msg));
|
||||
printf("node_priv=%p\n", node_priv);
|
||||
if (!expect_rx_payload) {
|
||||
printf("ERROR: did not expect rx_payload()\n");
|
||||
exit(-1);
|
||||
} else if (strcmp(expect_rx_payload, dump(msg))) {
|
||||
printf("ERROR: mismatches expected msg %s\n", expect_rx_payload);
|
||||
exit(-1);
|
||||
} else
|
||||
printf("ok: matches expected msg\n");
|
||||
expect_rx_payload = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *expect_tx_msg = NULL;
|
||||
int tx_msg(struct msgb *msg, void *node_priv)
|
||||
{
|
||||
printf("tx_msg() invoked by iuup_cn!\n");
|
||||
printf(" <-PDU- [IuUP]\n");
|
||||
printf("%s\n", dump(msg));
|
||||
printf("node_priv=%p\n", node_priv);
|
||||
if (!expect_tx_msg) {
|
||||
printf("ERROR: did not expect tx_msg()\n");
|
||||
exit(-1);
|
||||
} else if (strcmp(expect_tx_msg, dump(msg))) {
|
||||
printf("ERROR: mismatches expected msg %s\n", expect_tx_msg);
|
||||
exit(-1);
|
||||
} else
|
||||
printf("ok: matches expected msg\n");
|
||||
expect_tx_msg = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx_pdu(struct osmo_iuup_cn *cn, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
printf(" -PDU-> [IuUP]\n");
|
||||
printf("%s\n", dump(msg));
|
||||
rc = osmo_iuup_cn_rx_pdu(cn, msg);
|
||||
printf("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tx_payload(struct osmo_iuup_cn *cn, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
printf(" [IuUP] <-RTP-\n");
|
||||
printf("%s\n", dump(msg));
|
||||
rc = osmo_iuup_cn_tx_payload(cn, msg);
|
||||
printf("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void test_cn_session()
|
||||
{
|
||||
void *node_priv = (void*)0x2342;
|
||||
|
||||
struct osmo_iuup_cn_cfg cfg = {
|
||||
.node_priv = node_priv,
|
||||
.rx_payload = rx_payload,
|
||||
.tx_msg = tx_msg,
|
||||
};
|
||||
|
||||
struct osmo_iuup_cn *cn = osmo_iuup_cn_init(ctx, &cfg, __func__);
|
||||
OSMO_ASSERT(cn);
|
||||
|
||||
printf("\nSend IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack\n");
|
||||
expect_tx_msg = "8060dc5219495e3f00010111" /* RTP header */
|
||||
"e4002400"; /* IuUP Init Ack */
|
||||
rx_pdu(cn,
|
||||
msgb_from_hex("IuUP-Init",
|
||||
"8060dc5219495e3f00010111" /* <- RTP header */
|
||||
"e000df99" /* <- IuUP header */
|
||||
"160051673c01270000820000001710000100" /* IuUP params */));
|
||||
|
||||
#define RTP_HEADER "8060944c6256042c00010102"
|
||||
#define RTP_HEADER_PT112 "8070944c6256042c00010102"
|
||||
#define IUUP_HEADER "0100e2b3"
|
||||
#define RTP_PAYLOAD "6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0"
|
||||
printf("\nReceive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet\n");
|
||||
printf("i.e. should strip away " IUUP_HEADER "\n");
|
||||
expect_rx_payload = RTP_HEADER_PT112 "f03c" RTP_PAYLOAD;
|
||||
rx_pdu(cn,
|
||||
msgb_from_hex("IuUP-Data",
|
||||
RTP_HEADER IUUP_HEADER RTP_PAYLOAD));
|
||||
|
||||
printf("\nTransmit RTP. Expecting tx_msg() with inserted IuUP header\n");
|
||||
expect_tx_msg = RTP_HEADER "000002b3" RTP_PAYLOAD;
|
||||
tx_payload(cn,
|
||||
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
|
||||
|
||||
printf("\nMore RTP, each time the Frame Nr advances, causing a new header CRC.\n");
|
||||
expect_tx_msg = RTP_HEADER "0100e2b3" RTP_PAYLOAD;
|
||||
tx_payload(cn,
|
||||
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
|
||||
expect_tx_msg = RTP_HEADER "02007eb3" RTP_PAYLOAD;
|
||||
tx_payload(cn,
|
||||
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
|
||||
expect_tx_msg = RTP_HEADER "03009eb3" RTP_PAYLOAD;
|
||||
tx_payload(cn,
|
||||
msgb_from_hex("RTP data", RTP_HEADER "f03c" RTP_PAYLOAD));
|
||||
|
||||
printf("All done.\n");
|
||||
}
|
||||
|
||||
static const struct log_info_cat log_categories[] = {
|
||||
};
|
||||
|
||||
const struct log_info log_info = {
|
||||
.cat = log_categories,
|
||||
.num_cat = ARRAY_SIZE(log_categories),
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ctx = talloc_named_const(NULL, 0, __FILE__);
|
||||
void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
|
||||
osmo_init_logging2(ctx, &log_info);
|
||||
|
||||
test_cn_session();
|
||||
|
||||
talloc_free(msgb_ctx);
|
||||
return 0;
|
||||
}
|
||||
0
tests/iuup/iuup_test.err
Normal file
0
tests/iuup/iuup_test.err
Normal file
58
tests/iuup/iuup_test.ok
Normal file
58
tests/iuup/iuup_test.ok
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
Send IuUP Initialization. Expecting direct tx_msg() of the Initialization Ack
|
||||
-PDU-> [IuUP]
|
||||
8060dc5219495e3f00010111e000df99160051673c01270000820000001710000100
|
||||
tx_msg() invoked by iuup_cn!
|
||||
<-PDU- [IuUP]
|
||||
8060dc5219495e3f00010111e4002400
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
|
||||
Receive payload encapsulated in IuUP. Expecting rx_payload() of just RTP packet
|
||||
i.e. should strip away 0100e2b3
|
||||
-PDU-> [IuUP]
|
||||
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
rx_payload() invoked by iuup_cn!
|
||||
[IuUP] -RTP->
|
||||
8070944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
|
||||
Transmit RTP. Expecting tx_msg() with inserted IuUP header
|
||||
[IuUP] <-RTP-
|
||||
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
tx_msg() invoked by iuup_cn!
|
||||
<-PDU- [IuUP]
|
||||
8060944c6256042c00010102000002b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
|
||||
More RTP, each time the Frame Nr advances, causing a new header CRC.
|
||||
[IuUP] <-RTP-
|
||||
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
tx_msg() invoked by iuup_cn!
|
||||
<-PDU- [IuUP]
|
||||
8060944c6256042c000101020100e2b36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
[IuUP] <-RTP-
|
||||
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
tx_msg() invoked by iuup_cn!
|
||||
<-PDU- [IuUP]
|
||||
8060944c6256042c0001010202007eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
[IuUP] <-RTP-
|
||||
8060944c6256042c00010102f03c6cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
tx_msg() invoked by iuup_cn!
|
||||
<-PDU- [IuUP]
|
||||
8060944c6256042c0001010203009eb36cfb23bc46d18180c3e5ffe040045600005a7d35b625b80005fff03214ced0
|
||||
node_priv=0x2342
|
||||
ok: matches expected msg
|
||||
rc=0
|
||||
All done.
|
||||
@@ -11,8 +11,6 @@ AM_CFLAGS = \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMONETIF_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(LIBOSMOTRAU_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -37,10 +35,7 @@ mgcp_test_LDADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOTRAU_LIBS) \
|
||||
$(LIBRARY_DL) \
|
||||
$(LIBRARY_DLSYM) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
-lm \
|
||||
$(NULL)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ Testing CRCX
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
CRCX 2 1@mgw MGCP 1.0
|
||||
m: recvonly
|
||||
M: recvonly
|
||||
C: 2
|
||||
L: p:20
|
||||
|
||||
@@ -97,7 +97,7 @@ Response matches our expectations.
|
||||
Dummy packets: 2
|
||||
|
||||
================================================
|
||||
Testing MDCX4_ADDR000
|
||||
Testing MDCX4
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983216 1@mgw MGCP 1.0
|
||||
@@ -113,29 +113,6 @@ m=audio 4441 RTP/AVP 99
|
||||
m=audio 4441 RTP/AVP 99
|
||||
a=rtpmap:99 AMR/8000
|
||||
a=ptime:40
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing MDCX4
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983217 1@mgw MGCP 1.0
|
||||
M: sendrecv
|
||||
C: 2
|
||||
I: %s
|
||||
L: p:20, a:AMR, nt:IN
|
||||
|
||||
v=0
|
||||
o=- %s 23 IN IP4 5.6.7.8
|
||||
c=IN IP4 5.6.7.8
|
||||
t=0 0
|
||||
m=audio 4441 RTP/AVP 99
|
||||
a=rtpmap:99 AMR/8000
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
@@ -147,14 +124,14 @@ Dummy packets: 2
|
||||
================================================
|
||||
Testing MDCX4_PT1
|
||||
creating message from statically defined input:
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
---------8<---------
|
||||
MDCX 18983217 1@mgw MGCP 1.0
|
||||
M: sendrecv
|
||||
C: 2
|
||||
I: %s
|
||||
L: p:20-40, a:AMR, nt:IN
|
||||
L: p:20-40, a:AMR, nt:IN
|
||||
|
||||
|
||||
v=0
|
||||
o=- %s 23 IN IP4 0.0.0.0
|
||||
c=IN IP4 0.0.0.0
|
||||
t=0 0
|
||||
@@ -171,14 +148,14 @@ Dummy packets: 2
|
||||
|
||||
================================================
|
||||
Testing MDCX4_PT2
|
||||
Testing MDCX4_PT2
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983218 1@mgw MGCP 1.0
|
||||
M: sendrecv
|
||||
C: 2
|
||||
I: %s
|
||||
I: %s
|
||||
L: p:20-20, a:AMR, nt:IN
|
||||
L: p:20-20, a:AMR, nt:IN
|
||||
|
||||
v=0
|
||||
o=- %s 23 IN IP4 0.0.0.0
|
||||
c=IN IP4 0.0.0.0
|
||||
@@ -195,38 +172,14 @@ Dummy packets: 2
|
||||
Dummy packets: 2
|
||||
|
||||
================================================
|
||||
================================================
|
||||
Testing MDCX4_PT3
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983219 1@mgw MGCP 1.0
|
||||
M: sendrecv
|
||||
C: 2
|
||||
C: 2
|
||||
I: %s
|
||||
L: a:AMR, nt:IN
|
||||
|
||||
v=0
|
||||
o=- %s 23 IN IP4 5.6.7.8
|
||||
c=IN IP4 5.6.7.8
|
||||
t=0 0
|
||||
m=audio 4441 RTP/AVP 99
|
||||
a=rtpmap:99 AMR/8000
|
||||
a=ptime:40
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message with patched conn_id for comparison
|
||||
Response matches our expectations.
|
||||
(response contains a connection id)
|
||||
Dummy packets: 2
|
||||
|
||||
================================================
|
||||
Testing MDCX4_PT4
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983221 1@mgw MGCP 1.0
|
||||
m: sendrecv
|
||||
c: 2
|
||||
I: %s
|
||||
L: a:AMR, nt:IN
|
||||
|
||||
v=0
|
||||
o=- %s 23 IN IP4 0.0.0.0
|
||||
@@ -243,14 +196,14 @@ Dummy packets: 2
|
||||
(response contains a connection id)
|
||||
Dummy packets: 2
|
||||
|
||||
Dummy packets: 2
|
||||
================================================
|
||||
Testing MDCX4_SO
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983220 1@mgw MGCP 1.0
|
||||
M: sendonly
|
||||
MDCX 18983222 1@mgw MGCP 1.0
|
||||
M: sendonly
|
||||
C: 2
|
||||
I: %s
|
||||
L: p:20, a:AMR, nt:IN
|
||||
|
||||
v=0
|
||||
@@ -266,7 +219,7 @@ Response matches our expectations.
|
||||
using message with patched conn_id for comparison
|
||||
Response matches our expectations.
|
||||
(response contains a connection id)
|
||||
Response matches our expectations.
|
||||
|
||||
================================================
|
||||
Testing MDCX4_RO
|
||||
creating message from statically defined input:
|
||||
@@ -406,7 +359,7 @@ Testing CRCX
|
||||
I: %s
|
||||
C: 2
|
||||
|
||||
C: 2
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
@@ -464,6 +417,7 @@ checking response:
|
||||
|
||||
================================================
|
||||
Testing CRCX
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
CRCX 2 6@mgw MGCP 1.0
|
||||
M: recvonly
|
||||
@@ -492,7 +446,7 @@ Dummy packets: 2
|
||||
a=rtpmap:97 GSM-EFR/8000
|
||||
a=ptime:40
|
||||
|
||||
a=ptime:40
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message with patched conn_id for comparison
|
||||
Response matches our expectations.
|
||||
@@ -501,36 +455,12 @@ using message as statically defined for comparison
|
||||
|
||||
================================================
|
||||
Testing MDCX_TOO_LONG_CI
|
||||
================================================
|
||||
Testing MDCX_TOO_LONG_CI
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983224 1@mgw MGCP 1.0
|
||||
I: 123456789012345678901234567890123
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
(response does not contain a connection id)
|
||||
|
||||
================================================
|
||||
Testing CRCX
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
CRCX 2 7@mgw MGCP 1.0
|
||||
M: recvonly
|
||||
C: 2
|
||||
X
|
||||
L: p:20
|
||||
|
||||
v=0
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
MDCX 18983222 1@mgw MGCP 1.0
|
||||
I: 123456789012345678901234567890123
|
||||
|
||||
|
||||
---------8<---------
|
||||
checking response:
|
||||
using message as statically defined for comparison
|
||||
Response matches our expectations.
|
||||
@@ -548,7 +478,7 @@ Re-transmitting CRCX
|
||||
v=0
|
||||
c=IN IP4 123.12.12.123
|
||||
m=audio 5904 RTP/AVP 97
|
||||
c=IN IP4 123.12.12.123
|
||||
a=rtpmap:97 GSM-EFR/8000
|
||||
a=ptime:40
|
||||
|
||||
---------8<---------
|
||||
@@ -660,7 +590,7 @@ Testing packet loss calculation.
|
||||
creating message from statically defined input:
|
||||
---------8<---------
|
||||
DLCX 7 1@mgw MGCP 1.0
|
||||
---------8<---------
|
||||
I: %s
|
||||
C: 2
|
||||
|
||||
---------8<---------
|
||||
@@ -792,15 +722,6 @@ Stats: Jitter = 0, Transit = -144000
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 0, Transit = -144000
|
||||
In TS: 160160, dTS: 160, Seq: 1001
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
@@ -895,15 +816,6 @@ Stats: Jitter = 0, Transit = -144000
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
Output SSRC changed to 50607080
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 0, Transit = -144000
|
||||
In TS: 160160, dTS: 160, Seq: 1001
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
Output SSRC changed to 50607080
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
@@ -998,15 +910,6 @@ Stats: Jitter = 0, Transit = -144000
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
Output SSRC changed to 50607080
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
Out TS change: 123112, dTS: 160, Seq change: 975, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 0, Transit = -144000
|
||||
In TS: 160160, dTS: 160, Seq: 1001
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
Output SSRC changed to 50607080
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
@@ -1099,15 +1002,6 @@ Stats: Jitter = 0, Transit = -144000
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Stats: Jitter = 22, Transit = -32888
|
||||
In TS: 36888, dTS: 160, Seq: 25
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
Out TS change: 12000, dTS: 12000, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 0, Transit = -144000
|
||||
In TS: 160160, dTS: 160, Seq: 1001
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Out TS change: 160, dTS: 160, Seq change: 1, TS Err change: in +0, out +0
|
||||
Stats: Jitter = 21, Transit = -32888
|
||||
In TS: 160000, dTS: 0, Seq: 1000
|
||||
@@ -1247,7 +1141,7 @@ Testing no rtpmap name
|
||||
a=rtpmap:96 iLBC/8000
|
||||
a=fmtp:96 mode=20
|
||||
a=rtpmap:97 iLBC/8000
|
||||
a=fmtp:96 mode=20
|
||||
a=fmtp:97 mode=30
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-15
|
||||
a=recvonly
|
||||
@@ -1276,148 +1170,6 @@ p:10, a:PCMU -> p:10, a:PCMU
|
||||
p:10, a:PCMU -> p:10, a:PCMU
|
||||
p:10, a:PCMU -> p:10, a:PCMU
|
||||
'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
|
||||
p:10, a:PCMU -> p:10, a:PCMU
|
||||
'XXXX, p:10, a:PCMU' -> 'p:10, a:PCMU'
|
||||
'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
|
||||
'10,a:PCMU' -> 'a:PCMU'
|
||||
'10, a:PCMU' -> 'a:PCMU'
|
||||
'10,a: PCMU' -> 'a: PCMU'
|
||||
'10 ,a: PCMU' -> 'a: PCMU'
|
||||
', a:PCMU' -> 'a:PCMU'
|
||||
' a:PCMU' -> 'a:PCMU'
|
||||
'' -> '(null)'
|
||||
p10, aPCMU -> (null)
|
||||
'10,a :PCMU' -> '(null)'
|
||||
|
||||
Testing mgcp_codec_pt_translate()
|
||||
#0: same order, but differing payload type numbers
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
#1: different order and different payload type numbers
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
#2: both sides have the same payload_type numbers assigned to differing codecs
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 96 GSM-HR-08/8000/1 -> rc=0
|
||||
2: 97 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 96) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 96
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 97) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 97
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
#3: conn0 has no codecs
|
||||
- add codecs on conn0:
|
||||
(none)
|
||||
- add codecs on conn1:
|
||||
0: 96 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 97 GSM-HR-08/8000/1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
#4: conn1 has no codecs
|
||||
- add codecs on conn0:
|
||||
0: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
1: 0 PCMU/8000/1 -> rc=0
|
||||
2: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
(none)
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
#5: test AMR with differing octet-aligned settings
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
1: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=0 -> rc=0
|
||||
1: 121 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 121
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 121) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
|
||||
#6: test AMR with missing octet-aligned settings (defaults to 0)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
1: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 octet-aligned=unset -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
|
||||
#7: test AMR with NULL param (defaults to 0)
|
||||
- add codecs on conn0:
|
||||
0: 111 AMR/8000 octet-aligned=1 -> rc=0
|
||||
1: 112 AMR/8000 octet-aligned=0 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 122 AMR/8000 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> -22
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 122
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 122) -> 112
|
||||
#8: match FOO/8000/1 and FOO/8000 as identical, single channel is implicit
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 97 GSM-HR-08/8000 -> rc=0
|
||||
1: 0 PCMU/8000 -> rc=0
|
||||
2: 96 AMR/8000 octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
#9: match FOO/8000/1 and FOO as identical, 8k and single channel are implicit
|
||||
- add codecs on conn0:
|
||||
0: 0 PCMU/8000/1 -> rc=0
|
||||
1: 111 GSM-HR-08/8000/1 -> rc=0
|
||||
2: 112 AMR/8000/1 octet-aligned=1 -> rc=0
|
||||
- add codecs on conn1:
|
||||
0: 97 GSM-HR-08 -> rc=0
|
||||
1: 0 PCMU -> rc=0
|
||||
2: 96 AMR octet-aligned=1 -> rc=0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 112) -> 96
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 96) -> 112
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 0) -> 0
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 111) -> 97
|
||||
- mgcp_codec_pt_translate(conn1, conn0, 97) -> 111
|
||||
- mgcp_codec_pt_translate(conn0, conn1, 123) -> -22
|
||||
'XXXX,p:10,a:PCMU' -> 'p:10,a:PCMU'
|
||||
'10,a:PCMU' -> 'a:PCMU'
|
||||
'10, a:PCMU' -> 'a:PCMU'
|
||||
|
||||
@@ -35,7 +35,6 @@ mgcp_client_test_LDADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBRARY_DL) \
|
||||
$(LIBRARY_DLSYM) \
|
||||
$(LIBOSMONETIF_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -113,9 +113,9 @@ void test_response_cb(struct mgcp_response *response, void *priv)
|
||||
printf(" ptmap_len = %u\n", response->ptmap_len);
|
||||
for(i=0;i<response->ptmap_len;i++) {
|
||||
printf(" ptmap[%u].codec = %u\n", i, response->ptmap[i].codec);
|
||||
printf(" ptmap[%u].pt = %u\n", i, response->ptmap[i].pt);
|
||||
printf(" ptmap[%u].pt = %u\n", i, response->ptmap[i].pt);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
mgcp_trans_id_t dummy_mgcp_send(struct msgb *msg)
|
||||
@@ -157,7 +157,6 @@ void test_mgcp_msg(void)
|
||||
.ptmap[0].pt = 96,
|
||||
.ptmap_len = 1,
|
||||
.x_osmo_ign = MGCP_X_OSMO_IGN_CALLID,
|
||||
.x_osmo_osmux_cid = -1, /* wildcard */
|
||||
};
|
||||
|
||||
if (mgcp)
|
||||
@@ -181,7 +180,7 @@ void test_mgcp_msg(void)
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
||||
mgcp_msg.codecs_len = 2;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated CRCX message (three codecs, one with custom pt):\n");
|
||||
@@ -191,8 +190,8 @@ void test_mgcp_msg(void)
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE);
|
||||
mgcp_msg.codecs_len = 3;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated MDCX message:\n");
|
||||
mgcp_msg.verb = MGCP_VERB_MDCX;
|
||||
@@ -211,7 +210,7 @@ void test_mgcp_msg(void)
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
mgcp_msg.codecs_len = 2;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated MDCX message (three codecs, one with custom pt):\n");
|
||||
@@ -222,8 +221,8 @@ void test_mgcp_msg(void)
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
mgcp_msg.codecs_len = 3;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
mgcp_msg.codecs_len = 1;
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generated DLCX message:\n");
|
||||
mgcp_msg.verb = MGCP_VERB_DLCX;
|
||||
@@ -255,38 +254,6 @@ void test_mgcp_msg(void)
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generate X-Osmo-Osmux message:\n");
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.verb = MGCP_VERB_CRCX;
|
||||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
||||
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generate X-Osmo-Osmux message (fixed CID 2):\n");
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.verb = MGCP_VERB_CRCX;
|
||||
mgcp_msg.x_osmo_osmux_cid = 2;
|
||||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
||||
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Generate X-Osmo-Osmux message (MDCX):\n");
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
mgcp_msg.verb = MGCP_VERB_MDCX;
|
||||
mgcp_msg.x_osmo_osmux_cid = 2;
|
||||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE
|
||||
| MGCP_MSG_PRESENCE_X_OSMO_OSMUX_CID);
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("Overfolow test:\n");
|
||||
mgcp_msg.verb = MGCP_VERB_MDCX;
|
||||
mgcp_msg.presence =
|
||||
@@ -294,23 +261,11 @@ void test_mgcp_msg(void)
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
memset(audio_ip_overflow, 'X', sizeof(audio_ip_overflow));
|
||||
audio_ip_overflow[1] = '.';
|
||||
audio_ip_overflow[sizeof(audio_ip_overflow) - 1] = '\0';
|
||||
mgcp_msg.audio_ip = audio_ip_overflow;
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
OSMO_ASSERT(msg == NULL);
|
||||
|
||||
printf("IPv6 test:\n");
|
||||
mgcp_msg.verb = MGCP_VERB_MDCX;
|
||||
mgcp_msg.presence =
|
||||
(MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID |
|
||||
MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE |
|
||||
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT);
|
||||
mgcp_msg.audio_ip = "2001:db8:1::ab9:c0a8:102";
|
||||
mgcp->actual.remote_addr = "::1";
|
||||
msg = mgcp_msg_gen(mgcp, &mgcp_msg);
|
||||
printf("%s\n", (char *)msg->data);
|
||||
|
||||
printf("\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
@@ -331,7 +286,7 @@ void test_mgcp_client_cancel()
|
||||
| MGCP_MSG_PRESENCE_CONN_ID | MGCP_MSG_PRESENCE_CONN_MODE),
|
||||
.ptime = 20,
|
||||
.codecs[0] = CODEC_AMR_8000_1,
|
||||
.codecs_len = 1
|
||||
.codecs_len = 1
|
||||
};
|
||||
|
||||
printf("\n%s():\n", __func__);
|
||||
@@ -372,7 +327,7 @@ struct sdp_section_start_test {
|
||||
static struct sdp_section_start_test sdp_section_start_tests[] = {
|
||||
{
|
||||
.body = "",
|
||||
.expect_rc = 0,
|
||||
.expect_rc = -EINVAL,
|
||||
},
|
||||
{
|
||||
.body = "\n\n",
|
||||
@@ -411,79 +366,19 @@ static struct sdp_section_start_test sdp_section_start_tests[] = {
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\n\r\n"
|
||||
"m=audio 23\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_rc = -EINVAL,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r"
|
||||
"m=audio 23\r\n",
|
||||
.expect_rc = 0,
|
||||
.expect_rc = -EINVAL,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\n\r\r"
|
||||
"m=audio 23\r\n",
|
||||
.expect_rc = 0,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 1.2.3.4\r\n",
|
||||
.expect_params = {
|
||||
.audio_ip = "1.2.3.4",
|
||||
},
|
||||
.expect_rc = 0,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP6 2001:db8:1::ab9:c0a8:102\r\n",
|
||||
.expect_params = {
|
||||
.audio_ip = "2001:db8:1::ab9:c0a8:102",
|
||||
},
|
||||
.expect_rc = 0,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP6 1.2.3.4\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 ::1\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 notanip\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 1.2.3.4.5.6\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 1.2 .3\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 1.2 .3\r\n",
|
||||
.expect_rc = -22,
|
||||
},
|
||||
{
|
||||
.body = "some mgcp header data\r\nand header params"
|
||||
"\r\n\r\n"
|
||||
"c=IN IP4 \r\n",
|
||||
.expect_rc = -22,
|
||||
.expect_rc = -EINVAL,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -515,12 +410,7 @@ void test_sdp_section_start()
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "got audio_ip=\"%s\"\n", r->audio_ip);
|
||||
if (strcmp(r->audio_ip, t->expect_params.audio_ip)) {
|
||||
fprintf(stderr, "FAIL: Expected audio_ip=\"%s\"\n", t->expect_params.audio_ip);
|
||||
failures++;
|
||||
}
|
||||
fprintf(stderr, "got audio_port=%u\n", r->audio_port);
|
||||
fprintf(stderr, "got audio_port=%u\n", t->expect_params.audio_port);
|
||||
if (r->audio_port != t->expect_params.audio_port) {
|
||||
fprintf(stderr, "FAIL: Expected audio_port=%u\n", t->expect_params.audio_port);
|
||||
failures++;
|
||||
@@ -624,57 +514,6 @@ static void test_map_codec_to_pt_and_map_pt_to_codec(void)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void test_mgcp_client_e1_epname(void)
|
||||
{
|
||||
char *epname;
|
||||
|
||||
if (mgcp)
|
||||
talloc_free(mgcp);
|
||||
mgcp = mgcp_client_init(ctx, &conf);
|
||||
|
||||
/* Valid endpoint names */
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 1, 15, 64, 0);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 2, 14, 32, 0);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 3, 13, 32, 4);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 4, 12, 16, 0);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 5, 11, 16, 2);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 6, 10, 16, 4);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 7, 9, 16, 6);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 8, 8, 8, 0);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 9, 7, 8, 1);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 10, 6, 8, 2);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 11, 5, 8, 3);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 12, 4, 8, 4);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 13, 3, 8, 5);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 14, 2, 8, 6);
|
||||
printf("%s\n", epname);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 7);
|
||||
printf("%s\n", epname);
|
||||
|
||||
/* A few invalid enpoint names */
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 128, 0);
|
||||
OSMO_ASSERT(epname == NULL);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 1, 8, 16);
|
||||
OSMO_ASSERT(epname == NULL);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 0, 8, 2);
|
||||
OSMO_ASSERT(epname == NULL);
|
||||
epname = (char *)mgcp_client_e1_epname(ctx, mgcp, 15, 64, 8, 2);
|
||||
OSMO_ASSERT(epname == NULL);
|
||||
}
|
||||
|
||||
static const struct log_info_cat log_categories[] = {
|
||||
};
|
||||
|
||||
@@ -689,10 +528,9 @@ int main(int argc, char **argv)
|
||||
ctx = talloc_named_const(NULL, 1, "mgcp_client_test");
|
||||
msgb_talloc_ctx_init(ctx, 0);
|
||||
osmo_init_logging2(ctx, &log_info);
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
|
||||
log_set_category_filter(osmo_stderr_target, DLMGCP, 1, LOGL_DEBUG);
|
||||
@@ -704,7 +542,6 @@ int main(int argc, char **argv)
|
||||
test_sdp_section_start();
|
||||
test_map_codec_to_pt_and_map_pt_to_codec();
|
||||
test_map_pt_to_codec();
|
||||
test_mgcp_client_e1_epname();
|
||||
|
||||
printf("Done\n");
|
||||
fprintf(stderr, "Done\n");
|
||||
|
||||
@@ -1,138 +1,71 @@
|
||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
|
||||
DLMGCP MGW(mgw) Message buffer to small, can not generate MGCP message (SDP)
|
||||
DLMGCP MGCP client: using endpoint domain '@mgw'
|
||||
DLMGCP message buffer to small, can not generate MGCP message
|
||||
|
||||
test_mgcp_client_cancel():
|
||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
|
||||
DLMGCP MGCP client: using endpoint domain '@mgw'
|
||||
- composed msg with trans_id=1
|
||||
- not in queue yet, cannot cancel yet
|
||||
DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
|
||||
DLMGCP Cannot cancel, no such transaction: 1
|
||||
- enqueue
|
||||
- cancel succeeds
|
||||
DLMGCP MGW(mgw) Canceled transaction 1
|
||||
DLMGCP Canceled transaction 1
|
||||
- late response gets discarded
|
||||
DLMGCP MGW(mgw) MGCP client: Rx 200 1 OK
|
||||
DLMGCP MGW(mgw) Cannot find matching MGCP transaction for trans_id 1
|
||||
DLMGCP Cannot find matching MGCP transaction for trans_id 1
|
||||
- canceling again does nothing
|
||||
DLMGCP MGW(mgw) Cannot cancel, no such transaction: 1
|
||||
DLMGCP Cannot cancel, no such transaction: 1
|
||||
test_mgcp_client_cancel() done
|
||||
|
||||
test_sdp_section_start() test [0]:
|
||||
body: ""
|
||||
DLMGCP MGCP response contains no SDP parameters
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
DLMGCP MGCP response: cannot find start of SDP parameters
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [1]:
|
||||
body: "\n\n"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [2]:
|
||||
body: "\r\n\r\n"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [3]:
|
||||
body: "\n\r\n\r"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [4]:
|
||||
body: "some mgcp header data\r\nand header params\n\nm=audio 23\r\n"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=23
|
||||
|
||||
test_sdp_section_start() test [5]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nm=audio 23\r\n"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=23
|
||||
|
||||
test_sdp_section_start() test [6]:
|
||||
body: "some mgcp header data\r\nand header params\n\r\n\rm=audio 23\r\n"
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=23
|
||||
|
||||
test_sdp_section_start() test [7]:
|
||||
body: "some mgcp header data\r\nand header params\n\r\nm=audio 23\r\n"
|
||||
DLMGCP MGCP response contains no SDP parameters
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
DLMGCP MGCP response: cannot find start of SDP parameters
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [8]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\rm=audio 23\r\n"
|
||||
DLMGCP MGCP response contains no SDP parameters
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
DLMGCP MGCP response: cannot find start of SDP parameters
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [9]:
|
||||
body: "some mgcp header data\r\nand header params\n\r\rm=audio 23\r\n"
|
||||
DLMGCP MGCP response contains no SDP parameters
|
||||
got rc=0
|
||||
got audio_ip=""
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [10]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4\r\n"
|
||||
got rc=0
|
||||
got audio_ip="1.2.3.4"
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [11]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 2001:db8:1::ab9:c0a8:102\r\n"
|
||||
got rc=0
|
||||
got audio_ip="2001:db8:1::ab9:c0a8:102"
|
||||
got audio_port=0
|
||||
|
||||
test_sdp_section_start() test [12]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP6 1.2.3.4\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [13]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 ::1\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [14]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 notanip\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [15]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2.3.4.5.6\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [16]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [17]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 1.2 .3\r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
got rc=-22
|
||||
|
||||
test_sdp_section_start() test [18]:
|
||||
body: "some mgcp header data\r\nand header params\r\n\r\nc=IN IP4 \r\n"
|
||||
DLMGCP Failed to parse MGCP response header (audio ip)
|
||||
DLMGCP MGCP response: cannot find start of SDP parameters
|
||||
got rc=-22
|
||||
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
|
||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
|
||||
DLMGCP ptmap contains illegal mapping: codec=113 maps to pt=2
|
||||
DLMGCP ptmap contains illegal mapping: codec=0 maps to pt=100
|
||||
DLMGCP MGW(mgw) MGCP client: using endpoint domain '@mgw'
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su128-0@mgw), rate(128)/offset(0) combination is invalid!
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-1/su8-16@mgw), rate(8)/offset(16) combination is invalid!
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-0/su8-2@mgw), E1-timeslot number (0) is invalid!
|
||||
DLMGCP MGW(mgw) Cannot compose MGCP e1-endpoint name (ds/e1-15/s-64/su8-2@mgw), E1-timeslot number (64) is invalid!
|
||||
Done
|
||||
|
||||
@@ -84,45 +84,7 @@ L: p:20, a:GSM, nt:IN
|
||||
M: sendrecv
|
||||
X-Osmo-IGN: C
|
||||
|
||||
Generate X-Osmo-Osmux message:
|
||||
CRCX 13 23@mgw MGCP 1.0
|
||||
C: 2f
|
||||
I: 11
|
||||
L: p:20, a:GSM, nt:IN
|
||||
M: sendrecv
|
||||
X-Osmux: *
|
||||
|
||||
Generate X-Osmo-Osmux message (fixed CID 2):
|
||||
CRCX 15 23@mgw MGCP 1.0
|
||||
C: 2f
|
||||
I: 11
|
||||
L: p:20, a:GSM, nt:IN
|
||||
M: sendrecv
|
||||
X-Osmux: 2
|
||||
|
||||
Generate X-Osmo-Osmux message (MDCX):
|
||||
MDCX 17 23@mgw MGCP 1.0
|
||||
C: 2f
|
||||
I: 11
|
||||
L: p:20, a:GSM, nt:IN
|
||||
M: sendrecv
|
||||
X-Osmux: 2
|
||||
|
||||
Overfolow test:
|
||||
IPv6 test:
|
||||
MDCX 19 23@mgw MGCP 1.0
|
||||
C: 2f
|
||||
I: 11
|
||||
M: sendrecv
|
||||
|
||||
v=0
|
||||
o=- 2f 23 IN IP6 ::1
|
||||
s=-
|
||||
c=IN IP6 2001:db8:1::ab9:c0a8:102
|
||||
t=0 0
|
||||
m=audio 1234 RTP/AVP 3
|
||||
a=ptime:20
|
||||
|
||||
|
||||
|
||||
test_mgcp_client_cancel():
|
||||
@@ -163,24 +125,6 @@ test_sdp_section_start() test [7]:
|
||||
test_sdp_section_start() test [8]:
|
||||
|
||||
test_sdp_section_start() test [9]:
|
||||
|
||||
test_sdp_section_start() test [10]:
|
||||
|
||||
test_sdp_section_start() test [11]:
|
||||
|
||||
test_sdp_section_start() test [12]:
|
||||
|
||||
test_sdp_section_start() test [13]:
|
||||
|
||||
test_sdp_section_start() test [14]:
|
||||
|
||||
test_sdp_section_start() test [15]:
|
||||
|
||||
test_sdp_section_start() test [16]:
|
||||
|
||||
test_sdp_section_start() test [17]:
|
||||
|
||||
test_sdp_section_start() test [18]:
|
||||
110 => 96
|
||||
111 => 97
|
||||
112 => 98
|
||||
@@ -210,19 +154,4 @@ test_sdp_section_start() test [18]:
|
||||
2 <= 2
|
||||
100 <= 100
|
||||
|
||||
ds/e1-1/s-15/su64-0@mgw
|
||||
ds/e1-2/s-14/su32-0@mgw
|
||||
ds/e1-3/s-13/su32-4@mgw
|
||||
ds/e1-4/s-12/su16-0@mgw
|
||||
ds/e1-5/s-11/su16-2@mgw
|
||||
ds/e1-6/s-10/su16-4@mgw
|
||||
ds/e1-7/s-9/su16-6@mgw
|
||||
ds/e1-8/s-8/su8-0@mgw
|
||||
ds/e1-9/s-7/su8-1@mgw
|
||||
ds/e1-10/s-6/su8-2@mgw
|
||||
ds/e1-11/s-5/su8-3@mgw
|
||||
ds/e1-12/s-4/su8-4@mgw
|
||||
ds/e1-13/s-3/su8-5@mgw
|
||||
ds/e1-14/s-2/su8-6@mgw
|
||||
ds/e1-15/s-1/su8-7@mgw
|
||||
Done
|
||||
|
||||
@@ -13,3 +13,10 @@ AT_KEYWORDS([mgcp])
|
||||
cat $abs_srcdir/mgcp/mgcp_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([iuup])
|
||||
AT_KEYWORDS([iuup])
|
||||
cat $abs_srcdir/iuup/iuup_test.ok > expout
|
||||
cat $abs_srcdir/iuup/iuup_test.err > experr
|
||||
AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
Reference in New Issue
Block a user