Compare commits

..

141 Commits

Author SHA1 Message Date
Alexander Couzens
c56f68abd7 git-version-gen: revert to same version as libosmocore
OpenBSC required additional care because of an unusal .git location.
This is not need anymore for osmo-mgw

Change-Id: I5aad67612026947ad52cdc9477b603732c146e7a
2017-08-08 17:19:15 +02:00
Alexander Couzens
01fc7fb239 reword debian packages support
Remove old leftover from split of osmo-mgw out of openbsc.

Change-Id: I96a6a56c401833d053d48908872fb0474f5aec53
2017-08-08 17:18:40 +02:00
Neels Hofmeyr
370f4e3867 mgcp client: allow getting actual conf from opaque struct 2017-07-26 14:21:15 +02:00
Neels Hofmeyr
3acaadd44d prune public mgcpgw_client api 2017-07-26 14:21:15 +02:00
Neels Hofmeyr
f6a9cd53f4 split off osmo-mgw: remove files, apply build, rename
Add vty and logging previously used from libcommon

Rename libmgcp to libosmo-legacy-mgcp and install.

Use DLMGCP, not DMGCP.

Change-Id: I71a0a16ebaaef881c34235849601fc40aa12cfd7
Depends: libosmocore I09c587e2d59472cbde852d467d457254746d9e67
2017-07-26 14:21:15 +02:00
Neels Hofmeyr
f81151bd3f iudummy: remove public ranap_ue_conn_ctx_alloc
This function has been removed in osmo-iuh.
2017-07-25 15:32:42 +02:00
Neels Hofmeyr
9c0bab9b48 add msg type to SMS rx logging
Change-Id: I73ea4eebe57b2d1008045a27f174072178b9f077
2017-07-25 15:32:41 +02:00
Neels Hofmeyr
2fa9279702 set require IMEI by default
Change-Id: I91d8f3e79cdaa206f8cd32b42bd7c23933f9631a
2017-07-25 15:32:41 +02:00
Neels Hofmeyr
a622828806 msc_vlr tests: add IMEISV tests
Change-Id: I752afef2ae3ce04e813c7e9fea0e883e607c0e14
2017-07-25 15:32:41 +02:00
Neels Hofmeyr
2ab3af5263 vlr: LU FSM: enable Retrieve_IMEISV_If_Required
Change-Id: I121b95ad6d5ecb7603815eece2b43008de487a8a
2017-07-25 15:24:42 +02:00
Neels Hofmeyr
8571981205 vlr: place comments on if (0) cases 2017-07-25 15:24:42 +02:00
Neels Hofmeyr
2930c2d8ad .gitignore: cosmetic: use globs to ignore test binaries
Change-Id: I840e4333a4cad646d751ebafe7e0ef23e7a9c708
2017-07-25 15:24:42 +02:00
Neels Hofmeyr
6cd30366be move libiu to osmo-iuh/libosmo-ranap
Remove libiu here, use the functions from libosmo-ranap instead, by applying
the ranap_ / RANAP_ prefix.

Corresponding change-id in osmo-iuh.git is I6a3f7ad15be03fb94689b4af6ccfa828c25f45c0

Change-Id: Ib8c4fcdb4766c5e575618b95ce16dce51063206b
2017-07-25 15:24:41 +02:00
Neels Hofmeyr
ffb3e8d2ec MSC,SGSN: use OSMO_GSUP_PORT == 4222 instead of 2222
In SGSN, actually place the port in the SGSN config by default, so that the
gsup port may now be omitted in the VTY config (the IP address suffices).

Adjust the osmo-sgsn.cfg example.

Depends: I4222e21686c823985be8ff1f16b1182be8ad6175 (libosmocore)
Change-Id: I50f2040e2eb0baacb43849e93cfed10cbc2fc156
2017-07-25 15:18:48 +02:00
Neels Hofmeyr
b3f606a826 msc_vlr_tests: properly check BSSAP Clear and Iu Release
Change-Id: Ice8125decc1a663d95ae70418e151bff559b983b
2017-07-25 15:18:43 +02:00
Neels Hofmeyr
838a381b49 cosmetic: msc_vlr_tests: better place clear_cmd wrap, adjust printed msg
Change-Id: Iec6f03f97803b2604f0094260cba256e72ee67bd
2017-07-25 15:15:22 +02:00
Neels Hofmeyr
c5aed8c10e fix release upon IMSI Detach
In case of an IMSI Detach, we don't have a conn_fsm, yet we still need to send
release messages. Hence directly release the conn in msc_subscr_conn_close()
when there is no conn_fsm present.

Move the conn release actions from the conn_fsm cleanup function to new
function msc_subscr_conn_release_all(). From the FSM cleanup, call
msc_subscr_conn_close(), and invoke msc_subscr_conn_release_all() from there.

Document msc_subscr_conn_close() behavior.

Change-Id: Ied6981099605ad803f8ffed38f23ed8203a97727
2017-07-25 15:15:22 +02:00
Neels Hofmeyr
5b2283ba68 cosmetic: add info log for Iu Release tx
Change-Id: Ia64bc937d7f37ef6209efbdf884de61008f8816d
2017-07-25 15:15:22 +02:00
Neels Hofmeyr
f42457ec98 cosmetic: remove obsolete comment
Change-Id: Ie60e00e07b2129ac4bb3cac94921bf3c8d9cd861
2017-07-25 15:15:22 +02:00
Philipp Maier
09db3b69ed a-iface: move clear command to subscriber_conn.c
The clear command is currently triggered from the wrong place.
This is a fixup that corrects that. However, it will introduce
another problem: The clear command is not sent on detach.

Adjust test expectations.

Change-Id: Ia27d7e94cb11adf351457b3b0e98a5c9d5070fbf
2017-07-25 15:15:22 +02:00
Philipp Maier
4ebab46847 vty: Fixup sccp/ss7 configuration
The sccp/ss7 configuration is now fixed. The cs7 instance id is
implicitly detected from the bsc_addr or the msc_addr. Depending
on what is listed last. (I am not sure if that is wise, maybe
we should only use the local/bsc address to do the lookup).

Remove cs7-instance vty command

Modify VTY commands, so that the fixed API is used

Set msc->a.cs7_instance from the VTY to when msc/bsc addr is parsed

Fix the initalization to use osmo_sccp_simple_client_on_ss7_id() and
pass the cs7-instance id we determined from the vty.

The whole thing is not waterproof yet. We are still not at the
point where we allow to leave the local address out. This would
be fine, but when it is left out, the only way to determine the
cs7 instance is to use the msc_addr then.

We also might want to make sure to reach a state where all cs7
related config may be left out (like with the MSC)
2017-07-25 15:15:22 +02:00
Philipp Maier
19c4fd0562 fixup for: mgcp: display properly mgcp-messages in log 2017-07-25 15:15:22 +02:00
Philipp Maier
e198087a15 msc-vty-complete 2017-07-25 15:15:22 +02:00
Philipp Maier
50643e419d msc_vlr: Fix tests: accomodate a_iface_tx_clear_cmd()
msc_vlr_tests.c: wrap a_iface_tx_clear_cmd(), adjust test expectations.

Change-Id: I01c099e62b3e3d74c4f567c0654e748d9d7e45d4
2017-07-25 15:14:16 +02:00
Philipp Maier
e21c93fc96 osmo_msc: only clear A-Interface connections for GSM calls
The clear command is sent via the A-Interface for both,
A and IuCS connections. This is wrong.

Only send the clear command for connections related to
the A-Interface, which means only for connections where
the RAN is set to GERAN
2017-07-25 15:14:16 +02:00
Philipp Maier
956a2eb418 fixup: fix typo 2017-07-25 15:14:16 +02:00
Philipp Maier
90835e0083 mncc: make external mncc work
The external mncc currently does not work properly since the
MNCC_RTP_CREATE commands are removed due to the MSC-Split. It
is possible to operate without these commands, but then it is
not possible to route the RTP streams to an outside leg. Only
internal bridging is currenlty possible. This method is used
when the internal MNCC is enabled.

Add the missing MNCC_RTP_CREATE implementation.
Add logic to keep the old bridging mode working.
2017-07-25 15:14:16 +02:00
Philipp Maier
8643faad59 mgcp: display properly mgcp-messages in log
The generated mgcp messages are not displayed properly (stray
newlines). Also, the messages we receive are not displayed
at all.

Display generated and received messages in logtext, reformat
the strings properly so that the logtext does not get messed
up
2017-07-25 15:14:16 +02:00
Philipp Maier
03e1d5c7c5 fixup for: a_iface: fix missing clear command 2017-07-25 15:14:15 +02:00
Neels Hofmeyr
5bc821566f cosmetic: tweak error log in osmo_bsc_sigtran_init()
Change-Id: Iec3dbeb0ee1421129aaf9e313d616757955bee48
2017-07-25 15:14:15 +02:00
Philipp Maier
b67fb4fc63 a_iface: fix missing clear command
When a subscriber connection is freed on the MSC side (the
conversion is over) the MSC should send a clear command to
the BSC in order to inform the BSC that the connection is
over. Currently this step is missing. Instead we wait for
the BSC to issue a clear request. This is not as it should
be, connections should be actively cleared by the MSC.

Add the missing clear command
2017-07-25 15:14:15 +02:00
Philipp Maier
4b36c7a34e a_iface: fix missing log output 2017-07-25 15:14:15 +02:00
Philipp Maier
15b06b9d3c a_iface: fix missing const 2017-07-25 15:14:15 +02:00
Philipp Maier
241f119d8e a_iface: add missing static 2017-07-25 15:14:15 +02:00
Philipp Maier
5938727956 msc_ifaces: add checks for nullpointers 2017-07-25 15:14:15 +02:00
Neels Hofmeyr
ec49e842fe fixup: remove allocation/usage of iu struct again.
The allocation and usage of the iu struct was accidentally
re-introduced into a_iface_bssap.c.

Remove the allocation and the usage of iu struct.

Related to:
aoip: don't use iu struct: do not allocate unnecessary ue_conn_ctx
2017-07-25 15:14:15 +02:00
Philipp Maier
3ae6040afd osmo-bsc change bsc_handle_dt1() to bsc_handle_dt()
_dt1() is not applicable with the current setup, _dt() is
more accurate
2017-07-25 15:14:15 +02:00
Philipp Maier
9b0db3860c osmo-bsc: fix sccp name string
Change-Id: I4caf935fbeacc23d7a10766112ab844d6fc367ea
2017-07-25 15:14:15 +02:00
Philipp Maier
0317b106fe a_iface: remove unused variable
Change-Id: If964ac5344fa0275c07755b5a43d37ce186d3ca2
2017-07-25 15:14:15 +02:00
Philipp Maier
920420284c osmo-msc/a_iface/reset: add missing const
Change-Id: Id75918dfd891d9407a62a0b7cd9590932c858093
2017-07-25 15:14:15 +02:00
Philipp Maier
ae33266f6c osmo-bsc/sigtran: add missing const
Change-Id: I36404b34b8a85fc98670a3eeb8aaf29a4a6f10ea
2017-07-25 15:14:15 +02:00
Philipp Maier
ea452c93ca osmo-msc/a_iface: add missing assertions
Change-Id: If9eac28f70522edc42a9f169a7d12fed5936fb62
2017-07-25 15:14:15 +02:00
Philipp Maier
195cab61ab osmo-bsc: add missing comment
Change-Id: Iac59f2ff2f10997c636a8ac19427ed4a95dc99b5
2017-07-25 15:14:15 +02:00
Philipp Maier
23880357f2 osmo-bsc: add missing assertion
Change-Id: Ia7d4b0bff697acfa71ef616a12d78d17e3af4c20
2017-07-25 15:14:15 +02:00
Philipp Maier
2fd3a60ed8 osmo-msc: remove orphanned struct members
Change-Id: I229946cfe4ffa6de982586b1c2fa1117c3260e3a
2017-07-25 15:14:15 +02:00
Philipp Maier
569335bc34 osmo-msc: rename called/calling address in struct a_conn_info
Change-Id: I1b28652662d83f52db21cb78b512c501c7adf4bb
2017-07-25 15:14:15 +02:00
Philipp Maier
4c098cfb32 osmo-bsc: use better msc identifier
Using the MSC numbers in the logtext is not very expressive,
ise the SCCP-Addresses instead.

When creating the sccp instance and user, use more parseable
string than "MSC No.: n"

Change-Id: Ib56134193ba95538f63e09dc702dc3ff0e827a02
2017-07-25 15:14:15 +02:00
Philipp Maier
d3f2ae8d6a osmo-bsc: fix typo
Change-Id: I154db5bcaada8f5503ca8700644abf00f511ff6e
2017-07-25 15:14:15 +02:00
Philipp Maier
faa1b9dd0a osmo-bsc: vty: fix error message
The warning message that is displayed when a non standard SSN is
set is confusing.

Make warning message more expressive.

Change-Id: I5283bcc5acf4739d468fe43937f0e59f44dee3d9
2017-07-25 15:14:15 +02:00
Neels Hofmeyr
f85f656b18 build: osmo-bsc_nat: add missing sigtran LDADD
Change-Id: Ia3031232a3a44b8e8a665610a2fd1cf0a7e55b22
2017-07-25 15:14:15 +02:00
Philipp Maier
51442a7886 osmo-bsc: rename calling_addr to msc_addr
The variable name "calling_addr" is not very expressive. Change
the variable name to "msc_addr".

Change-Id: I3a43880d4172063e78bfef1556dbb037f20a9a99
2017-07-25 15:14:15 +02:00
Philipp Maier
88824c7c7d osmo-bsc: change calling/called addr in VTY
The vty commands:
 called-addr my_msc
 calling-addr my_bsc

are not very expressive to the user. Change the command
names into something more expressive:

 msc-addr my_msc
 bsc-addr my_bsc

Also change the function and variable names accordingly

Change-Id: I8d46aad01fb80afcaccb966fadd6b2ecbd1a1f9e
2017-07-25 15:14:15 +02:00
Philipp Maier
6202b37a0b osmo-bsc: change calling/called_addr variable names
"calling_address" and "called_address" is not very expressive.

change the respective struct memeber names of bsc_msc_data to
bsc_addr and msc_addr to increase readability of the code.

Change-Id: I63b2e810b97131c690edd5a9cc5c7b3b54ec5e12
2017-07-25 15:14:15 +02:00
Philipp Maier
dd93694587 osmo-bsc: check configured sccp addresses before start
do not start unless the user has configured sufficient SCCP
addresses via VTY. Do not accept address that lack point codes
or ssn

Change-Id: I42b4fb0ef93dec225e220e88e1b92664b9b55be3
2017-07-25 15:14:14 +02:00
Philipp Maier
ead844e65e osmo-bsc: make sure only default SSNs are used
The VTY technically allows setting custom values for the
SSN. However, SSN values and their purposes are well
standardized.

If the user has configured an SSN, check that is compliant
to the standard. If not, warn and ignore the setting by
using the stanard SSN.

If the user left out the SSN, automatically use the standard
SSN.

Change-Id: Ib34fe0474f625b964dbfedfb4263fb0b5f976bdc
2017-07-25 15:14:14 +02:00
Philipp Maier
d6278889c4 cosmetic: fix typo in log output
Change-Id: I8d76a61e28c0677e121586c1fe4666baa7196b18
2017-07-25 15:14:14 +02:00
Philipp Maier
2535d12377 osmo-bsc: only clear connections of a specific MSC
The BSC clears all connections on reception of a
BSSAP RESET, however, the RESET command must not
affect the connections of other MSCs.

Ensure that only the connections of the MSC who
actually sent the BSSAP RESET are cleared.

Change-Id: I68fe2eadeae8ba6b6728fced42f6308e9b2d997a
2017-07-25 15:14:14 +02:00
Philipp Maier
ed21f2eecf osmo-bsc: Make SCCP-Addresses configurable via VTY
Add VTY commands to configure the sccp-address of the BSC
and the one of the MSC.

Change-Id: I49cedc0ce339defa6fb354f6fb9b1af7820da7cc
2017-07-25 15:14:14 +02:00
Philipp Maier
31b05fe895 common-vty: add ss7 nodes commands to VTY
The current VTY implementation has no knowledge about the
libosmo-sccp nodes and therefor can not resolve parent nodes,
nor decide if we deal with a config node.

Change-Id: I815a57ed6270bd55c25ee9a8f45026d4aaad9004
2017-07-25 15:14:14 +02:00
Philipp Maier
e4b33dd303 osmo-msc: finish msc-sided reset
finish the implementation for msc sided reset, automatically
register connecting BSCs.

Ensure that all sccp connections are cleared when the reset
procedure executes.

Change-Id: Iba3f5523795c6972600bbfda2a02b06ba84ea12d
2017-07-25 15:14:14 +02:00
Philipp Maier
184892b371 msc_vlr: fix linker problem in testcase
Swap libmsc.a and libcommon-cs.a to make symbols from
libcommon-cs.a available to libmsc.a

Change-Id: I16fdd58d0b542aca987865a6bb7ca0f996693e81
2017-07-25 15:14:14 +02:00
Philipp Maier
8a3c5a0699 mgcp: Fix missing call id in DLCX
The call id field in the DLCX message is missing. Use the endpoint
id as call id in all CRCX and DLCX messages.

Change-Id: I8b78b76126c63c4882e982c64c3953dbe1dab179
2017-07-25 15:14:14 +02:00
Philipp Maier
7d5e706964 reset: fix allocation and add deallocator for reset procedure
When the reset is started, state machines are allocated. The user
must provide a correctly filled structure where the reset start
function adds the state machine into.

This is prone to errors, besides of that, a proper deallocator
function which tears down the osmo fsm is missing.

make a more cofmortable allocator function and add deallocator
function.

Change-Id: I0054fb31589fb9f4c63c45df436e83448c59bd97
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
04d1ca7895 aoip: don't use iu struct: move rtp ports from .iu to new subscr_conn.rtp
Change-Id: Ib1a84b0733655b2e87c1598ae9df0640cdca833b
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
e4dc412e7b aoip: don't use iu struct: do not allocate unnecessary ue_conn_ctx
Change-Id: I06c4c3eac3cf95cef78d49f1462096d6350f226a
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
1f94ba58ea osmo_bsc_main: use osmo_sccp_make_addr_pc_ssn() for SCCP addresses
Change-Id: I91eb444def4715652f7988189a58e1168ef15d19
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
104548372c AoIP+3G: use one common SCCP client for A and IuCS
Move osmo_sccp_simple_client() setup out of iu_init() and a_init().
In msc_main.c and sgsn_main.c, initialize the STP connection first and then
pass to iu_init() and a_init().

This allows serving 3G (IuCS) and 2G (A) from one and the same MSC instance.

Since both OsmoHNBGW and OsmoBSC are using PC 23 by default now, move BSC to PC
42 (because OsmoBSC typically has vty port 4242, bla).

Also:
a_iface.c: remove now unused defines
a_init(): remove osmo_ss7_init() call that duplicated msc_main.c

Change-Id: I963a94e1a0bfc455992d22940dcc9c67c44570b9
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
79b2387c0b msc: re-enable iu_init()
Change-Id: Iee7fa94d3f6880847020f3e0dfe7ed7672d4fb23
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
39bc234f9e a_init: use name arg for sccp client and user bind
Change-Id: Ie281e8a486471e1d48a1444a07795e97c17627f2
2017-07-25 15:14:14 +02:00
Philipp Maier
3a401548ce a_iface: fix typo in function name
Change-Id: Ia545a0daec6336732f1bcaa01e27c843eb732dd8
2017-07-25 15:14:14 +02:00
Philipp Maier
cc12b708a7 a_iface: Check if channel type and speech codec list are successful
Currently we do not check for errors during the generation of
channel type and speech codec list. This might blow an assertion
in gsm0808_create_ass if the generated data is invalid. So
we need to check beforehand.

Change-Id: Ifa7ba00e0d731a3c43a8dbfac893c71d63559eb5
2017-07-25 15:14:14 +02:00
Philipp Maier
114c4ff913 rsl: fix stray line break in logtext
The log output from the rsl layer injects line breaks at wrong
places in the log. This messes up the logtext. This commit fixes
the problem.

Change-Id: Ibebffd52a551ead0f5486a56a92774204b337c7d
2017-07-25 15:14:14 +02:00
Philipp Maier
9fa9783dc6 mgcp: fix line-break problem in log
When the mgcp_client prints MGCP strings in the log text, it does
not remove the line break before printing. This will mess up
the log text. This patch removes the line break characters before
printing properly.

Change-Id: I7fce23a50371ce94a8f2d8aef2fe9d2001d41b8c
2017-07-25 15:14:14 +02:00
Neels Hofmeyr
3d09bbbbc4 apply function renames in merged libosmocore patches
Change-Id: Ic659d6d79a6284732e1837f8b0947e8a128ddd87
2017-07-25 15:14:14 +02:00
Philipp Maier
34ed929877 osmo-bsc: react on reset requests from MSC
The bsc side currently can not receive reset commands from an
MSC. This patch adds required functionality to receive a reset
command and acknowlege it properly. The effects are the same
as with when sending resets (all drop all ongoing calls and
sccp connections)

Change-Id: I44c7e54c845948c54614b36d97d2ba1e760ac46b
2017-07-25 15:14:14 +02:00
Philipp Maier
fef5ee84f2 libcommon-cs: genralize a interface reset fsm
The AoIP standard also describes an MSC->BSC reset procedure. We
currently do not implement it. However, the fsm that is used to
issue the reset request from the bsc side is not generalized. This
patch generalizes the code in order to be able to use the same
code on the MSC side to perform a reset procedure from there.

Change-Id: I65e20bebb126ba35122ca3a545393d18fcadf5ad
2017-07-25 15:14:14 +02:00
Philipp Maier
ad228e16cf fixup: remove unused counter
Forgot to remove the counter struct osmo_timer_list msc_reset_timer;
Needs to be fixuped into the reset handling patches

Change-Id: I6d397188732f4593edc12459de6f3b5f47b7f06a
2017-07-25 15:14:14 +02:00
Philipp Maier
869842e16c sccp-lite: remove old sccp-lite code
in osmo_bsc_sccp.c all code is commented out. There is no point
in keeping the file. This commit deletes it.

Change-Id: I5c9f15a658c41fd872db7b078d38fbfdeb2bdcbd
2017-07-25 15:14:14 +02:00
Philipp Maier
3bac10082a osmo-bsc: Send USSD notification when an MSC loss is detected
the old sccp-lite based imlementation offered support for sending
an USSD notification as soon as a loss of the MSC connection is
detected. This is done before forcefully dropping the affected
connection.

This commit ports the feature to the new libosmo-sigtran
implementation.

NOTE: I do not know if this works and I also do not really
understand how this is even possible. Sending an USSD notification
would rquire the subscriber to be properly attached? When the MSC
is lost this almost not possible since no backend to authenticate
against is available.

Change-Id: Idaadf8d708608843e3c36ed35b3661b48096c21b
2017-07-25 15:14:14 +02:00
Philipp Maier
158d842969 cosmetic: make function names in a_iface_bssap more expressive.
The function names in a_iface_bssap.c are not very expressive.
The problem not only exists on the API side, but also for static
functions. This patch replaces the function names with more
expressive names.

Change-Id: I1cdf37e4034ed8a9536c253c13910fc436c66f04
2017-07-25 15:14:14 +02:00
Philipp Maier
a2ec888287 cosmetic: more expressive function names in a_iface
The function names if the API function in a_iface.c are not
very expressive. Besides of that, the prototypes are in the
wrong header file. This commit gives the function more
expressive names and moves the prototypes in the right header
file.

Change-Id: I6af4b7deed9d11ac5fe188eb5625fba50caad7c1
2017-07-25 15:14:14 +02:00
Philipp Maier
1a331b5405 fixup: return with value in void function
Change-Id: Iab2569205eac9cb96a7d6f756f087413af5fc68c
2017-07-25 15:14:13 +02:00
Philipp Maier
83d75bb19a mgcp: make bts base port configurable
Currently the rtp base port of the BTS is hardcoded (4000) and not
configurable. This patch adds VTY configuration options to make
it adjustable.

Change-Id: I76e008eb0bd95b2941b67ea2fbdc1a82eef3cc5f
2017-07-25 15:14:13 +02:00
Philipp Maier
7a8e4a0215 Revert "mgcp: make sure all endpoints are closed on startup"
Clearing all endpoints by sending a DLCX on startup has ben found
to be a bit too offensive. It also will not help against
inconsitancies that may occour during runtime (e.g. an overheard
DLCX during regular call teardown).

This reverts commit b669ea94cb78fd9b56ee8dd9392538151349f8ba.

Change-Id: Ia3bd8bfe9a09e300cf11629f7d7e3012ca8f394d
2017-07-25 15:14:13 +02:00
Philipp Maier
d4d44cacbc mgcp: Make sure endpoint is free on CRCX
The MSC is aware of the assigned endpoints at all times, so it
will not assign an occupied endpoint to someone else. However,
if it has just restarted, there maybe lingering open endpoints.

This patch introduces a fairly simple soultion. Before a new
endpoint is seized (CRCX), a DLCX is send in advance. If the
endpoint was still occupied with a dead connection, it will
be freed. If it was free anyway, the DLCX will just have no
effect.

Change-Id: I7990e9e7c4c8101b8772ab5505a7cc11f8f7cd23
2017-07-25 15:14:13 +02:00
Philipp Maier
554488dee8 a_iface_bssap: clear lingering subscriber connections on reset
When the BSC is vanishing, the subscriber connections will stay
active until the MSC is instructed via tha A interface to clear
the connections. Unfortunately, this will most likely not be
the case because the BSC will most likeley have lost all its
state and does not know about the old connections anymore.

This patch fixes the problem by looping through the list with
the active gsm subscriber connections and clearing them manually
when the reset from the BSC is received. Only connections by the
bsc who actually executes the reset are affected. Connections
from other BSCs will not be touched.

Change-Id: Ic2b43b937d08a6dea4fe70dbc3eb722323338dc1
2017-07-25 15:14:13 +02:00
Philipp Maier
d46c75dac9 cosmetic: fix typo
Change-Id: I2cfea36a5626605ecb72d0f0927ac1a731aa1609
2017-07-25 15:14:13 +02:00
Philipp Maier
2a6629b27e mgcp: make sure all endpoints are closed on startup
If the MSC is crashing and restarting, it may leave some endpoints
open. The endpoints can not be re-used until they are deleted
(DLCX). This patch sends a DLCX to all possible endpoints (usually
this is in a countable range) in order to clear possible open
endpoints from a previous run

Change-Id: I9de2f67ffe08b2d76574ef4470c7a9767ca74702
2017-07-25 15:14:13 +02:00
Philipp Maier
95e1a3b53c mgcp: make structs accessible from outside
struct mgcpgw_client and struct mgcp_inuse_endpoint are not
accessible from outside, making it difficult to look in the
mgcp client properties and status. The commit moves the
structs into the header file.

Change-Id: I20dcdaac013e3bcbd870eaf34a17598eac373f95
2017-07-25 15:14:13 +02:00
Philipp Maier
00a0862e9c mgcp: release no longer used endpoint identifiers
When an MGCP endpoint is deleted, we need to mark its endpoint
id as unused, so other calls can used it. This is currently not
happening. This patch fixes that.

Change-Id: I346affea940efb3a55e9b34c28a6cbe676d57d56
2017-07-25 15:14:13 +02:00
Philipp Maier
d4195472f5 mgcp: improve endpoint management
Currently the assignment of endpoint identifiers works by just
incrementing a counter. The mgcpgw only has a limited amount
of endpoint identifiers avaliable, this means we will run out
of endpoints after only a few calls.

This commit adds a mechanism to keep track of used endpoint
identifiers so unused endpoint identifiers can be re-used

Change-Id: I081f9178975b6593a7ab8de5261a29a1d43d36a3
2017-07-25 15:14:13 +02:00
Philipp Maier
741b987923 mgcp: use mgcp DLCX command to terminate endpoint after call is done
Currently no DLCX command is sent to the mgcpgw when a call is over,
this leaves the endpoint open. This means that the endpoint can not
never be reused by other calls. This patch adds a DLCX that
terminates the the endpoint when the call is done.

Change-Id: Ifc5a7a62fc07b4b7fee612d52e949fcd6a8e04ed
2017-07-25 15:14:13 +02:00
Philipp Maier
3398964176 mgcp: add DLCX command to mgcpgw client
The mgcpgw client currently lacks support for DLCX. This patch
adds a generator function to generate a DLCX command as well.

Change-Id: I1ac4635fc1371f2d3a46815f26a1f9ede3eedafa
2017-07-25 15:14:13 +02:00
Philipp Maier
c5bb5816cd cosmetic: fixing coding style
Change-Id: I9dc3b1d2990ad6c89932d77632c3b22748e8361e
2017-07-25 15:14:13 +02:00
Philipp Maier
1c832b34b1 fixup: in osmo-bsc-sigtran.h header (bsc_msc_data.h) was missing
Change-Id: I4220bc9a3a6f13fd6b09c3a7edadea5b8823d1c5
2017-07-25 15:14:13 +02:00
Philipp Maier
88e9ecbfb5 osmo-bsc: Handle RESET/RESET-ACK properly
Improve the way the BSC executes its RESET/RESET-ACK sequence.
Currently only a simple bool variable serves as a state holder.
We set this variable to true when we receive the RESET-ACK
message. Unfortunately no further checking is done. This
patch replaces the old mechanism with a more elaborated
implementation which also detects a loss of the connection
and makes sure to reconnect properly afterwards. Also the
all open connections are closed on connection loss

Change-Id: I876319b15103cc395e74597a52ce4d1a934915f4
2017-07-25 15:14:13 +02:00
Philipp Maier
3386a8791e sccp: Use osmo-stp instead of direct server/client connection
This patch adjusts the code to use osmo-stp. This is only an
intermediate solution, since we still have hardcoded parameter.
Next step is to use the VTY options from libosmo-sigtran to
issue the configurations.

Change-Id: I2b02bf159051beed6ff3afc66fcfb7a30e8d2541
2017-07-25 15:14:13 +02:00
Philipp Maier
2529f046e8 fixup for: aoip: signal channel type to BSC
The channel type and the speech codec element is now
signalled to the BSC. The BSC checks both fields and
select a codec by its preference. The choosen speech
codec and the choosen channel (type) is returned to
the MSC. Currently the MSC ignores the return values

Change-Id: I5c422a1e831f572e493db9756cf45e7a0b7ec7d0
2017-07-25 15:14:13 +02:00
Philipp Maier
ae819a1be4 aoip: signal channel type to BSC
obtain the permitted speech and the prefered channel parameters
and signal it to the MSC with the channel type field.

Change-Id: I642480fa408dee7a4f40f7aab95f40383b3e91af
2017-07-25 15:14:13 +02:00
Philipp Maier
2878423b95 osmo-msc: Integrate A interface into existing call control
The MSC already has some basic call control handling mechanism, that
was primarily used with 3G before. However, the already existing
code that handles the 3G calls is also perfectly fine for handling
2G calls. This commit integrates the A interface without breaking
it for 3G.

Change-Id: Ib61cf2987823958314c9016d5a3f494c1aaaabbc
2017-07-25 15:14:13 +02:00
Philipp Maier
714b2281b8 osmo-bsc: Negotiate rtp ip address/port with BTS
This patch adds the support for the RTP IP-Address/Port assignment.
The post communicated via the assignment request is now transmitted
via RSL/IPACC to the BTS. The Response containing the RX-Port at
the BTS side is communicated back to the MSC.

Since we plan to add a private MGCPGW to each BSC, this has to
be extended. Currently it only creates a direct connection to
the BTS. This will be introduced with a future patch.

Change-Id: I693e428b6bfdd8534eb5b88fa4d47dac20db88ea
2017-07-25 15:14:13 +02:00
Philipp Maier
c7aa82b109 fixup: Hexdump for incoming unit data was missing
Change-Id: Ie867455f12eba5b5091424796a9dbf5140890e41
2017-07-25 15:14:13 +02:00
Neels Hofmeyr
d69cdf75e0 comment: fixme to cleanup MGCP ports
Change-Id: Ibbd8279116262c3adcb35e9f3d417b6d7da40d5a
Related: OS#2279
2017-07-25 15:14:13 +02:00
Neels Hofmeyr
6cad4c3e7f msc: enable basic CTRL commands
So far CTRL was not used by anyone, and was still disabled from the initial
implementation of the OsmoMSC. Now we need it in osmo-gsm-tester.

Only add the MSC specific CTRL commands, the bsc_base_ctrl_cmds_install() still
needs to be split up.

Change-Id: I373279ccea8941c237330c3404c63d4924c5ffa0
2017-07-25 15:14:13 +02:00
Neels Hofmeyr
2238185739 sgsn: add missing osmo_ss7_init()
Change-Id: Ibcf73383bbf2b94f308b4d5bc4e69b652c73ce6e
2017-07-25 15:14:13 +02:00
Neels Hofmeyr
456dbb8070 drop libosmo-ranap from sms_queue test
Change-Id: I93d4a7d54c39cc2c1b4e8e30df7b0b410ac00786
2017-07-25 15:14:13 +02:00
Neels Hofmeyr
a3df1f8732 wip iudummy struct osmo_sccp_addr -- drop this?
Change-Id: Ie1df8502c0b1a504b552cfe24ddc2717b672c300
2017-07-25 15:14:13 +02:00
Philipp Maier
e66311b1bd WIP: Integrate AoIP into MSC
Change-Id: Iaf7deff397ec95b744fe287e713bbdd6a1ee73cf
2017-07-25 15:12:32 +02:00
Philipp Maier
7e77a293a5 libmsc: make pitfall in gsm0408_dispatch() more obvious
The function gsm0408_dispatch() accepts a message buffer pointer
and accesses the l3h pointer. Even in a properly allocated
message buffer, this may lead into a segfault if the user forgets
to set the l3h pointer. This commit adds assertions to popup a
more expressive error message.

Change-Id: I43bd9bd1c170559aaa8dacaef25dba090744bcd5
2017-07-25 01:06:57 +02:00
Philipp Maier
2932bc4955 WIP: Integrate AoIP into OsmoBSC
Change-Id: I5ae4e05ee7c57cad341ea5e86af37c1f6b0ffa77
2017-07-25 01:06:57 +02:00
Harald Welte
1168969378 WIP: Port to new libosmo-sigtran API (with proper M3UA for Iuh)
This changes over to the new libosmo-sigtran API with support for
proper SCCP/M3UA/SCTP stacking, as mandated by 3GPP specifications for
the IuCS and IuPS interfaces.

Only the ASP (client) is used, assuming that both the HNB-GWs and RNCs
as well as the MSCs and SGSNs are all connecting as ASP to some STP/SGW
which offers M3UA server functionality as well as point-code and/or
global title based routing.

Change-Id: I450e22d46e47eec350a152f7832428f226bf17fc
Tweaked-by: nhofmeyr (test expectation)
2017-07-25 01:06:57 +02:00
Daniel Willmann
3d5990fc65 examples/sgsn: Use osmo-hlr with auth-policy remote by default
Change-Id: Ie3b2013198d3e2b780a4e31c36b89b58129dcacd
2017-07-25 01:06:56 +02:00
Daniel Willmann
21ca60807c contrib: Change systemd requirements so the services connect properly
Change-Id: Ib1b3c640ddd81927a60ee307c4b0cb90fd83eebe
2017-07-25 01:06:56 +02:00
Daniel Willmann
aba422a6cc examples: Change IP address of config files
This helps in providing 3G software packages for the sysmoNITB hardware.

Change-Id: Ie3a25f6771ed6e620cb2b315638c622a9a24e530
2017-07-25 01:06:56 +02:00
Daniel Willmann
d0a25a05a2 contrib: Add osmo-msc service file
Change-Id: Ifdaf4107167c84af8a616f4ee792d5a34495564b
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
bbc26f444a temporary dev: set debug log level almost everywhere
Change-Id: I851d8d5791caa301c0b06eca295d05837834a3ee
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
c49975de02 log protocol discriminators and message types by name
Change-Id: Ida205d217e304337d816b14fd15e2ee435e7397d
Depends: libosmocore change-id I0fca8e95ed5c2148b1a7440eff3fc9c7583898df
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
6a87169a31 mgcp: hack RAB success from nano3G: patch first RTP payload
The ip.access nano3G needs the first RTP payload's first two bytes to read hex
'e400', or it will reject the RAB assignment. Add flag
patched_first_rtp_payload to mgcp_rtp_state to detect the first RTP payload on
a stream, and overwrite its first bytes with e400. This should probably be
configurable, but seems to not harm other femto cells (as long as we patch only
the first RTP payload in each stream). Only do this when sending to the BTS
side.

Change-Id: I5eff04dcb0936e21690e427ae5e49228cd459bd4
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
3a0b3b2182 msc_vlr_tests: add missing wrap for ranap_iu_tx_release()
It seems merely luck that the tests worked so far without this wrap. Adjust
test logs now indicating where we actually send an Iu Release -- and leaving
gaping holes where we don't. To be fixed in another commit.

Change-Id: I770f5f058c72539ff4a2913b076fee8440248fd9
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
3f8fdf0e7a Implement IuCS (large refactoring and addition)
osmo-nitb becomes osmo-msc
add DIUCS debug log constant
add iucs.[hc]
add msc vty, remove nitb vty
add libiudummy, to avoid linking Iu deps in tests
Use new msc_tx_dtap() instead of gsm0808_submit_dtap()
libmgcp: add mgcpgw client API
bridge calls via mgcpgw

mgcp: hack RAB success from nano3G: patch first RTP payload
The ip.access nano3G needs the first RTP payload's first two bytes to read hex
'e400', or it will reject the RAB assignment. Add flag
patched_first_rtp_payload to mgcp_rtp_state to detect the first RTP payload on
a stream, and overwrite its first bytes with e400. This should probably be
configurable, but seems to not harm other femto cells (as long as we patch only
the first RTP payload in each stream). Only do this when sending to the BTS
side.

Change-Id: I5b5b6a9678b458affa86800afb1ec726e66eed88
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
36e6e7f074 sgsn init: pass sgsn_config pointer to sgsn_vty_init(), not sgsn_parse_config
In an upcoming commit, sgsn_vty_init() will require access to the global sgsn
config struct to initialize a generic VTY command with the proper config
destination address, see Change-Id I5b5b6a9678b458affa86800afb1ec726e66eed88.

Change-Id: Ie6b6e5422987586531a898e0c5b867623dbecb0f
2017-07-25 01:06:56 +02:00
Neels Hofmeyr
03f51df03c mscsplit: various preparations to separate MSC from BSC
Disable large parts of the code that depend on BSC presence. The code sections
disabled by #if BEFORE_MSCSPLIT shall be modified or dropped in the course of
adding the A-interface.

Don't set msg->lchan nor msg->dst.
Don't use lchan in libmsc.
Decouple lac from bts.

Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication:
Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to
different interfaces depending on the actual subscriber connection.
While iu_tx() is going to be functional fairly soon, the a_tx() is going to be
just a dummy for some time (see comment).
Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer
and an indicator for the Integrity Protection status on Iu (to be fully
implemented in later commits).
Add lac member to gsm_subscriber_connection, to allow decoupling from
bts->location_area_code. The conn->lac will actually be set in iu.c in an
upcoming commit ("add iucs.[hc]").

move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi().

libmsc: duplicate gsm0808 / gsm48 functions (towards BSC).
In osmo-nitb, libmsc would directly call the functions on the BSC level, not
always via the bsc_api. When separating libmsc from libbsc, some functions are
missing from the linkage.
Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also
add a _tx to gsm0808_cipher_mode():
* add msc_gsm0808_tx_cipher_mode() (dummy/stub)
* add msc_gsm48_tx_mm_serv_ack()
* add msc_gsm48_tx_mm_serv_rej()
Call these from libmsc instead of
* gsm0808_cipher_mode()
* gsm48_tx_mm_serv_ack()
* gsm48_tx_mm_serv_rej()
Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places.

Remove internal RTP streaming code; OsmoNITB supported that, but for OsmoMSC,
this will be done with an external MGCP gateway.

Remove LCHAN_MODIFY from internal MNCC state machine.

Temporarily disable all paging to be able to link libmsc without libbsc.
Skip the paging part of channel_test because the paging is now disabled.
Employ fake paging shims in order for msc_vlr_tests to still work.

msc_compl_l3(): publish in .h, tweak return value.  Use new libmsc enum values
for return val, to avoid dependency on libbsc headers.  Make callable from
other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c

add gsm_encr to subscr_conn
move subscr_request to gsm_subscriber.h
subscr_request_channel() -> subscr_request_conn()
move to libmsc: osmo_stats_vty_add_cmds()
gsm_04_08: remove apply_codec_restrictions()
gsm0408_test: use NULL for root ctx
move to libbsc: gsm_bts_neighbor()
move to libbsc: lchan_next_meas_rep()
move vty config for t3212 to network level (periodic lu)
remove unneccessary linking from some tests
remove handle_abisip_signal()
abis_rsl.c: don't use libvlr from libbsc

gsm_subscriber_connection: put the LAC here, so that it is available without
accessing conn->bts. In bsc_api.c, place this lac in conn for the sake of
transition: Iu and A will use this new field to pass the LAC around, but in a
completely separate OsmoBSC this is not actually needed. It can be removed
again from osmo-bsc.git when the time has come.

Siemens MRPCI: completely drop sending the MRPCI messages for now, they shall
be added in osmo-bsc once the A-Interface code has settled. See OS#2389.

Related: OS#1845 OS#2257 OS#2389
Change-Id: Id3705236350d5f69e447046b0a764bbabc3d493c
2017-07-25 01:06:28 +02:00
Harald Welte
46f4f14024 SGSN: Don't indicate GERAN in Iu mode PDP CTX ACT REQ to GGSN
Change-Id: Ifd9ff4342de342475609bad0257a23c50290e23b
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
ecd8c048fc IuPS: explicitly check RAN type; move comment
Change-Id: I054d72590dfb2012f6f8506d3a5f8fd2953194e1
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
ed739b9dac IuPS: don't require an MM context for Iu Release
Change-Id: I8b4d08b3ee8add1f1d54efb13985eabe0c9d31f3
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
5322912630 SI3: indicate R99+ MSC to GSM MS to enable UMTS AKA
Change-Id: I796e1f4281628061f4522c43c549de9e751bc045
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
772205aae1 cosmetic: make osmo-python-tests dependency more accurate
Change-Id: I4f84a13b7fa6ec4173bdc155e6114d4d7328b619
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
853883d1f6 osmo-nitb: change default db name to sms.db
libvlr now delegates subscriber management to osmo-hlr, so the database no
longer represents a HLR. It basically only stores SMS, so reflect that fact in
the default database name.

Change-Id: I3289d68d3eb63aff940b48a25b584d5e83cd0197
2017-07-23 04:30:44 +02:00
Neels Hofmeyr
6a29d326e0 Add msc_vlr test suite for MSC+VLR end-to-end tests
Change-Id: If0e7cf20b9d1eac12126955b2f5f02bd8f1192cd
2017-07-23 04:30:05 +02:00
Harald Welte
2483f1b050 Use libvlr in libmsc (large refactoring)
Original libvlr code is by Harald Welte <laforge@gnumonks.org>,
polished and tweaked by Neels Hofmeyr <nhofmeyr@sysmocom.de>.

This is a long series of trial-and-error development collapsed in one patch.
This may be split in smaller commits if reviewers prefer that. If we can keep
it as one, we have saved ourselves the additional separation work.

SMS:

The SQL based lookup of SMS for attached subscribers no longer works since the
SQL database no longer has the subscriber data. Replace with a round-robin on
the SMS recipient MSISDNs paired with a VLR subscriber RAM lookup whether the
subscriber is currently attached.

If there are many SMS for not-attached subscribers in the SMS database, this
will become inefficient: a DB hit returns a pending SMS, the RAM lookup will
reveal that the subscriber is not attached, after which the DB is hit for the
next SMS. It would become more efficient e.g. by having an MSISDN based hash
list for the VLR subscribers and by marking non-attached SMS recipients in the
SMS database so that they can be excluded with the SQL query already.

There is a sanity limit to do at most 100 db hits per attempt to find a pending
SMS. So if there are more than 100 stored SMS waiting for their recipients to
actually attach to the MSC, it may take more than one SMS queue trigger to
deliver SMS for subscribers that are actually attached.

This is not very beautiful, but is merely intended to carry us over to a time
when we have a proper separate SMSC entity.

Introduce gsm_subscriber_connection ref-counting in libmsc.

Remove/Disable VTY and CTRL commands to create subscribers, which is now a task
of the OsmoHLR. Adjust the python tests accordingly.

Remove VTY cmd subscriber-keep-in-ram.

Use OSMO_GSUP_PORT = 4222 instead of 2222. See
I4222e21686c823985be8ff1f16b1182be8ad6175.

So far use the LAC from conn->bts, will be replaced by conn->lac in
Id3705236350d5f69e447046b0a764bbabc3d493c.

Related: OS#1592 OS#1974
Change-Id: I639544a6cdda77a3aafc4e3446a55393f60e4050
2017-07-23 04:08:43 +02:00
Harald Welte
b8b85a1b2e Add libvlr implementation
Original libvlr code is by Harald Welte <laforge@gnumonks.org>,
polished and tweaked by Neels Hofmeyr <nhofmeyr@sysmocom.de>.

This is a long series of trial-and-error development collapsed in one patch.
This may be split in smaller commits if reviewers prefer that. If we can keep
it as one, we have saved ourselves the additional separation work.

Related: OS#1592
Change-Id: Ie303c98f8c18e40c87c1b68474b35de332033622
2017-07-21 18:32:03 +02:00
Neels Hofmeyr
53edff3c70 jenkins: pass proper configure flags to make distcheck
Enable various components according to the build matrix during make distcheck.
Add python tests, osmo-bsc, nat, ...

Change-Id: Ic724cf61d44409337414dc58c8795896b4b97a8a
2017-07-21 03:48:01 +02:00
Neels Hofmeyr
625e05a6b2 fix make distcheck with python tests
- bscs.config needed by the vty tests was not picked up as a dist file, because
  its suffix is not 'cfg'. Rename to *.cfg. Apply this rename in
  vty_test_runner.py and osmo-bsc_nat.cfg.
- Remove restart counters after external tests, otherwise distcheck complains
  about uncleaned files.
- Add contrib/ipa.py to EXTRA_DIST, hence add a Makefile.am to contrib/.
  Otherwise the python tests cannot find that dependency.

Change-Id: I42b55cb1125099afc3a8e3f87c0e398426b2e2a9
2017-07-21 03:39:38 +02:00
Neels Hofmeyr
3355fd674f logging: auth request: use hexdump without spaces for RAND, AUTN
Change-Id: Ie16bb2c01e770914f411bfb34b523c56ea9fab81
2017-07-13 02:17:39 +00:00
Neels Hofmeyr
f2ba81303e gsup_client: allow passing a unit id to identify with HLR
Before, each GSUP client would contact the HLR with an identical unit id, i.e.
"SGSN-00-00-00-00-00-00", with the result that some messages were sucked off by
the wrong client.

Pass explicit unit name from each gsup client user, so that OsmoMSC is "MSC"
and OsmoSGSN is "SGSN". Hence the HLR can properly route the messages.

Todo: also set some values instead of the zeros.

Unrelated cosmetic change while editing the arguments: gsup_client_create()'s
definition's oap client config arg name mismatched the one used in the
declaration. Use oapc_config in both.

Change-Id: I0a60681ab4a4d73e26fe8f0637447db4b6fe6eb2
2017-07-13 02:17:31 +00:00
Neels Hofmeyr
cbafa255cc GPRS/IuPS: remove all 3G authentication dev hacks
UMTS auth works now with the external OsmoHLR.

Change-Id: Ie42945bb687b077fd0ee430c2711d19782151610
2017-07-13 02:17:23 +00:00
Neels Hofmeyr
14ce472225 git-version-gen: look for .git in ./, not ../
Change-Id: Ic71cfb8dde0a43325b50c75aae1e6ef3c3008501
2017-07-12 23:28:38 +00:00
Neels Hofmeyr
c00d016e20 join openbsc/.gitignore with .gitignore
Change-Id: Ib2120592749e85a4d13f6668e198857e3bddcf1e
2017-07-12 23:28:24 +00:00
Neels Hofmeyr
f29ff888a2 jenkins: apply rename to osmo-msc in log marker
Change-Id: I8ca9a1a8bdb5b9615df5f19f0c1017cb9383f6ee
2017-07-12 23:28:11 +00:00
Neels Hofmeyr
29b9206e80 move openbsc/* to repos root
This is the first step in creating this repository from the legacy openbsc.git.

Like all other Osmocom repositories, keep the autoconf and automake files in
the repository root. openbsc.git has been the sole exception, which ends now.

Change-Id: I9c6f2a448d9cb1cc088cf1cf6918b69d7e69b4e7
2017-07-12 23:17:10 +00:00
Neels Hofmeyr
9e3c66b181 jenkins: fix build of --enable-iu: use osmo-iuh tag 'old_sua'
We are building with libosmo-sccp tag 'old_sua' until the new sigtran has
been applied. Since osmo-iuh commit
  0f88c110093935305143987638e46dc6db304a3e
  "migrate osmo-hnbgw to libosmo-sigtran's SCCP/M3UA"
osmo-iuh requires libosmo-sccp master. A similar 'old_sua' tag is in place in
osmo-iuh.git, to match libosmo-sccp 'old_sua'. Do that to fix the jenkins
build of --enable-iu.

Change-Id: I70f731db0b74ed48ae6dd713ed4c3247222ef0de
2017-07-12 23:42:21 +02:00
113 changed files with 3490 additions and 11798 deletions

View File

@@ -1,3 +1,3 @@
[gerrit]
host=gerrit.osmocom.org
project=osmo-mgw
project=openbsc

View File

@@ -17,17 +17,10 @@ SUBDIRS = \
$(NULL)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
libosmo-legacy-mgcp.pc \
libosmo-mgcp-client.pc \
libosmo-mgcp.pc \
$(NULL)
pkgconfig_DATA = libosmo-legacy-mgcp.pc
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = git-version-gen osmoappdesc.py .version
@RELMAKE@
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:

53
README
View File

@@ -1,28 +1,39 @@
About OsmoMGW
About OpenBSC
=============
OsmoMGW originated from the OpenBSC project, which started as a minimalistic
all-in-one implementation of the GSM Network. In 2017, OpenBSC had reached
maturity and diversity (including M3UA SIGTRAN and 3G support in the form of
IuCS and IuPS interfaces) that naturally lead to a separation of the all-in-one
approach to fully independent separate programs as in typical GSM networks.
OpenBSC started as a minimalistic all-in-one implementation of the GSM Network,
with particular emphasis on the functionality typically provided by the BSC,
MSC, HLR, VLR and SMSC. Today it is a growing suite of libraries and programs,
implementing protocol stacks and functional elements, including
OsmoMGW was one of the parts split off from the old openbsc.git. It originated
as a solution to merely navigate RTP streams through a NAT, but has since
matured to a Media Gateway implementation that is capable of streaming RTP for
2G (AoIP) and 3G (IuCS) GSM networks as well as (still not implemented at time
of writing) transcoding between TRAU, various RTP payloads and IuUP.
* OsmoBSC - a pure GSM BSC, speaking Abis/IP to the BTS and A/IP to the MSC
* OsmoBSC-MGCP - MGCP helper to the OsmoBSC software
* OsmoNITB - a BSC+MSC+VLR+HLR+SMSC "Network in the box".
* OsmoMSC - a voice CN with A/IP and IuCS/IP towards the BSC and/or HNB-GW
* OsmoSGSN - a GPRS SGSN with Gb/IP and IuPS/IP towards the PCU and/or HNB-GW
* Osmo-GbProxy - a Proxy to aggregate many Gb links as one Gb link to the SGSN
* OsmoBSCNAT - a gateway aggregating many A links as one A link to the MSC
* OsmoGTPHUB - a hub aggregating many GTP links (between SGSN and GGSN)
* ipaccess-utils - some tools to discover + configure ip.access nanoBTS
* bs11_config - a tool to configure the Siemens BS-11 microBTS
The OsmoMGW program exposes an MGCP interface towards clients like OsmoMSC and
OsmoBSC, and receives and sends RTP streams as configured via MGCP.
Various interfaces towards the BTS are supported, among which are:
The libosmo-mgcp-client library exposes utilities used by e.g. OsmoMSC (found
in osmo-msc.git) to instruct OsmoMGW via its MGCP service.
* Classic A-bis over E1 using a mISDN based E1 interface. In other
words, you can connect existing GSM Base Transceiver Station (BTS)
through E1 to OpenBSC. So far, we have made it work with the Siemens BS-11,
various Ericsson RBS2xxx BTS models and the Nokia MetroSite.
The libosmo-mgcp library exposes MGCP server utilities used by e.g. OsmoBSC-NAT
(found in osmo-bsc.git) to navigate RTP streams through a NAT.
(At time of writing, this is still called libosmo-legacy-mgcp.)
* A-bis over IP as used by the ip.access nanoBTS product family as well as
the Open Source OsmoBTS software (by the same authors as OpenBSC). OsmoBTS
in turn supports various transceiver hardware, including the sysmoBTS
product family, as well as SDR transceivers supported by OsmoTRX, such as
the UmTRX or USRP boardss.
Find OsmoMGW issue tracker and wiki online at
https://osmocom.org/projects/osmo-mgw
https://osmocom.org/projects/osmo-mgw/wiki
* IuCS and IuPS over IP towards an HNB-GW (see osmo-iuh) for UMTS (3G)
voice and data links.
Find OpenBSC online at
http://openbsc.osmocom.org/
Harald Welte <laforge@gnumonks.org>

View File

@@ -1,29 +0,0 @@
# When cleaning up this file upon a release:
#
# - Note that the release version number is entirely unrelated to the API
# versions. A release version 5.2.3 may happily have an API version of 42:7:5.
#
# - Bump API version in src/lib*/Makefile.am files according to chapter
# "Library interface versions" of the libtool documentation.
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
#
# - Iff the 'current' API version has changed, rename debian/lib*.install
#
# API version bumping for the impatient:
# LIBVERSION=c:r:a (current:revision_of_current:backwards_compat_age)
# 5:2:4 means that
# - this implements version 5 of the API;
# - this is the 2nd (compatible) revision of API version 5;
# - this is backwards compatible to all APIs since 4 versions ago,
# i.e. callers that need API versions from 1 to 5 can use this.
#
# Bumping API versions recipe:
# If the library source code has changed at all since the last update, r++;
# If any interfaces have been added, removed, or changed since the last update, c++, r=0;
# If any interfaces have been added since the last public release, a++;
# If any interfaces have been removed or changed since the last public release, a=0.
#
#library what description / commit summary line
libosmo-mgcp API/ABI change parse and represent connection identifiers as hex strings
libosmo-mgcp API/ABI change connection identifiers are assigned by the server, not CA
libosmo-mgcp-client API/ABI change parse and store connection identifier in response

View File

@@ -12,10 +12,6 @@ AC_CONFIG_TESTDIR(tests)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl include release helper
RELMAKE='-include osmo-release.mk'
AC_SUBST([RELMAKE])
dnl checks for programs
AC_PROG_MAKE_SET
AC_PROG_CC
@@ -39,22 +35,9 @@ AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.1.0)
AC_ARG_ENABLE(sanitize,
[AS_HELP_STRING(
[--enable-sanitize],
[Compile with address sanitizer enabled],
)],
[sanitize=$enableval], [sanitize="no"])
if test x"$sanitize" = x"yes"
then
CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
fi
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.9.5)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
# Enable/disable transcoding within osmo-bsc_mgcp?
AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])],
@@ -131,24 +114,15 @@ AM_CONFIG_HEADER(bscconfig.h)
AC_OUTPUT(
libosmo-legacy-mgcp.pc
libosmo-mgcp-client.pc
libosmo-mgcp.pc
include/Makefile
include/osmocom/Makefile
include/osmocom/legacy_mgcp/Makefile
include/osmocom/mgcp_client/Makefile
include/osmocom/mgcp/Makefile
src/Makefile
src/libosmo-legacy-mgcp/Makefile
src/libosmo-mgcp-client/Makefile
src/libosmo-mgcp/Makefile
src/osmo-bsc_mgcp/Makefile
src/osmo-mgw/Makefile
tests/Makefile
tests/atlocal
tests/legacy_mgcp/Makefile
tests/mgcp_client/Makefile
tests/mgcp/Makefile
doc/Makefile
doc/examples/Makefile
contrib/Makefile

View File

@@ -1,278 +0,0 @@
#!/usr/bin/python3
# -*- mode: python-mode; py-indent-tabs-mode: nil -*-
"""
/*
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
"""
import struct, random, sys
class IPA(object):
"""
Stateless IPA protocol multiplexer: add/remove/parse (extended) header
"""
version = "0.0.5"
TCP_PORT_OML = 3002
TCP_PORT_RSL = 3003
# OpenBSC extensions: OSMO, MGCP_OLD
PROTO = dict(RSL=0x00, CCM=0xFE, SCCP=0xFD, OML=0xFF, OSMO=0xEE, MGCP_OLD=0xFC)
# ...OML Router Control, GSUP GPRS extension, Osmocom Authn Protocol
EXT = dict(CTRL=0, MGCP=1, LAC=2, SMSC=3, ORC=4, GSUP=5, OAP=6)
# OpenBSC extension: SCCP_OLD
MSGT = dict(PING=0x00, PONG=0x01, ID_GET=0x04, ID_RESP=0x05, ID_ACK=0x06, SCCP_OLD=0xFF)
_IDTAG = dict(SERNR=0, UNITNAME=1, LOCATION=2, TYPE=3, EQUIPVERS=4, SWVERSION=5, IPADDR=6, MACADDR=7, UNIT=8)
CTRL_GET = 'GET'
CTRL_SET = 'SET'
CTRL_REP = 'REPLY'
CTRL_ERR = 'ERR'
CTRL_TRAP = 'TRAP'
def _l(self, d, p):
"""
Reverse dictionary lookup: return key for a given value
"""
if p is None:
return 'UNKNOWN'
return list(d.keys())[list(d.values()).index(p)]
def _tag(self, t, v):
"""
Create TAG as TLV data
"""
return struct.pack(">HB", len(v) + 1, t) + v
def proto(self, p):
"""
Lookup protocol name
"""
return self._l(self.PROTO, p)
def ext(self, p):
"""
Lookup protocol extension name
"""
return self._l(self.EXT, p)
def msgt(self, p):
"""
Lookup message type name
"""
return self._l(self.MSGT, p)
def idtag(self, p):
"""
Lookup ID tag name
"""
return self._l(self._IDTAG, p)
def ext_name(self, proto, exten):
"""
Return proper extension byte name depending on the protocol used
"""
if self.PROTO['CCM'] == proto:
return self.msgt(exten)
if self.PROTO['OSMO'] == proto:
return self.ext(exten)
return None
def add_header(self, data, proto, ext=None):
"""
Add IPA header (with extension if necessary), data must be represented as bytes
"""
if ext is None:
return struct.pack(">HB", len(data) + 1, proto) + data
return struct.pack(">HBB", len(data) + 1, proto, ext) + data
def del_header(self, data):
"""
Strip IPA protocol header correctly removing extension if present
Returns data length, IPA protocol, extension (or None if not defined for a give protocol) and the data without header
"""
if not len(data):
return None, None, None, None
(dlen, proto) = struct.unpack('>HB', data[:3])
if self.PROTO['OSMO'] == proto or self.PROTO['CCM'] == proto: # there's extension which we have to unpack
return struct.unpack('>HBB', data[:4]) + (data[4:], ) # length, protocol, extension, data
return dlen, proto, None, data[3:] # length, protocol, _, data
def split_combined(self, data):
"""
Split the data which contains multiple concatenated IPA messages into tuple (first, rest) where rest contains remaining messages, first is the single IPA message
"""
(length, _, _, _) = self.del_header(data)
return data[:(length + 3)], data[(length + 3):]
def tag_serial(self, data):
"""
Make TAG for serial number
"""
return self._tag(self._IDTAG['SERNR'], data)
def tag_name(self, data):
"""
Make TAG for unit name
"""
return self._tag(self._IDTAG['UNITNAME'], data)
def tag_loc(self, data):
"""
Make TAG for location
"""
return self._tag(self._IDTAG['LOCATION'], data)
def tag_type(self, data):
"""
Make TAG for unit type
"""
return self._tag(self._IDTAG['TYPE'], data)
def tag_equip(self, data):
"""
Make TAG for equipment version
"""
return self._tag(self._IDTAG['EQUIPVERS'], data)
def tag_sw(self, data):
"""
Make TAG for software version
"""
return self._tag(self._IDTAG['SWVERSION'], data)
def tag_ip(self, data):
"""
Make TAG for IP address
"""
return self._tag(self._IDTAG['IPADDR'], data)
def tag_mac(self, data):
"""
Make TAG for MAC address
"""
return self._tag(self._IDTAG['MACADDR'], data)
def tag_unit(self, data):
"""
Make TAG for unit ID
"""
return self._tag(self._IDTAG['UNIT'], data)
def identity(self, unit=b'', mac=b'', location=b'', utype=b'', equip=b'', sw=b'', name=b'', serial=b''):
"""
Make IPA IDENTITY tag list, by default returns empty concatenated bytes of tag list
"""
return self.tag_unit(unit) + self.tag_mac(mac) + self.tag_loc(location) + self.tag_type(utype) + self.tag_equip(equip) + self.tag_sw(sw) + self.tag_name(name) + self.tag_serial(serial)
def ping(self):
"""
Make PING message
"""
return self.add_header(b'', self.PROTO['CCM'], self.MSGT['PING'])
def pong(self):
"""
Make PONG message
"""
return self.add_header(b'', self.PROTO['CCM'], self.MSGT['PONG'])
def id_ack(self):
"""
Make ID_ACK CCM message
"""
return self.add_header(b'', self.PROTO['CCM'], self.MSGT['ID_ACK'])
def id_get(self):
"""
Make ID_GET CCM message
"""
return self.add_header(self.identity(), self.PROTO['CCM'], self.MSGT['ID_GET'])
def id_resp(self, data):
"""
Make ID_RESP CCM message
"""
return self.add_header(data, self.PROTO['CCM'], self.MSGT['ID_RESP'])
class Ctrl(IPA):
"""
Osmocom CTRL protocol implemented on top of IPA multiplexer
"""
def __init__(self):
random.seed()
def add_header(self, data):
"""
Add CTRL header
"""
return super(Ctrl, self).add_header(data.encode('utf-8'), IPA.PROTO['OSMO'], IPA.EXT['CTRL'])
def rem_header(self, data):
"""
Remove CTRL header, check for appropriate protocol and extension
"""
(_, proto, ext, d) = super(Ctrl, self).del_header(data)
if self.PROTO['OSMO'] != proto or self.EXT['CTRL'] != ext:
return None
return d
def parse(self, data, op=None):
"""
Parse Ctrl string returning (var, value) pair
var could be None in case of ERROR message
value could be None in case of GET message
"""
(s, i, v) = data.split(' ', 2)
if s == self.CTRL_ERR:
return None, v
if s == self.CTRL_GET:
return v, None
(s, i, var, val) = data.split(' ', 3)
if s == self.CTRL_TRAP and i != '0':
return None, '%s with non-zero id %s' % (s, i)
if op is not None and i != op:
if s == self.CTRL_GET + '_' + self.CTRL_REP or s == self.CTRL_SET + '_' + self.CTRL_REP:
return None, '%s with unexpected id %s' % (s, i)
return var, val
def trap(self, var, val):
"""
Make TRAP message with given (vak, val) pair
"""
return self.add_header("%s 0 %s %s" % (self.CTRL_TRAP, var, val))
def cmd(self, var, val=None):
"""
Make SET/GET command message: returns (r, m) tuple where r is random operation id and m is assembled message
"""
r = random.randint(1, sys.maxsize)
if val is not None:
return r, self.add_header("%s %s %s %s" % (self.CTRL_SET, r, var, val))
return r, self.add_header("%s %s %s" % (self.CTRL_GET, r, var))
def verify(self, reply, r, var, val=None):
"""
Verify reply to SET/GET command: returns (b, v) tuple where v is True/False verification result and v is the variable value
"""
(k, v) = self.parse(reply)
if k != var or (val is not None and v != val):
return False, v
return True, v
if __name__ == '__main__':
print("IPA multiplexer v%s loaded." % IPA.version)

View File

@@ -1,11 +1,4 @@
#!/usr/bin/env bash
# jenkins build helper script for openbsc. This is how we build on jenkins.osmocom.org
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
set -ex
@@ -14,18 +7,22 @@ deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
rm -rf "$inst"
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
"$deps"/libosmocore/contrib/verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
osmo-build-dep.sh libosmo-abis
osmo-build-dep.sh libosmo-netif
if [ "x$IU" = "x--enable-iu" ]; then
sccp_branch="old_sua"
osmo_iuh_branch="old_sua"
fi
PARALLEL_MAKE="" osmo-build-dep.sh libsmpp34
set +x
echo
@@ -42,8 +39,6 @@ $MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
LD_LIBRARY_PATH="$inst/lib" \
DISTCHECK_CONFIGURE_FLAGS="$MGCP --enable-vty-tests --enable-external-tests" \
DISTCHECK_CONFIGURE_FLAGS="--enable-osmo-bsc --enable-nat $SMPP $MGCP $IU --enable-vty-tests --enable-external-tests" \
$MAKE distcheck \
|| cat-testlogs.sh
osmo-clean-workspace.sh

View File

@@ -1,11 +0,0 @@
[Unit]
Description=Osmocom Media Gateway (MGW)
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-mgw -s -c /etc/osmocom/osmo-mgw.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

43
debian/changelog vendored
View File

@@ -1,46 +1,3 @@
osmo-mgw (1.2.0) unstable; urgency=medium
[ Neels Hofmeyr ]
* jenkins: use osmo-clean-workspace.sh before and after build
* vty: skip installing cmds now always installed by default
* mgcp-client vty: use name 'mgw' instead of 'mgcpgw'
* mgcp client: vty: tweak doc strings
[ Philipp Maier ]
* sdp: refactoring sdp parser/generator
* cosmetic: rename bts_codec to codec_str
* cosmetic: fix coding style for mgcp_parse_sdp_data()
* cosmetic: fix commenting style
* cosmetic: correct whitespaces
* client: fix stderror logging in unit-test
* client: add unified function to generate MGCP messages
* client: add ip address parsing to the client
* protocol: allow wildcarded DLCX
* mgcp: remove port/timeslot calculator functions from mgcp.h
* network: add separate log category
* cosmetic: make dummy packet handling more explicit
* network: autdetect rtp bind ip-address
* network: fix rtp packet length
* network: remove unused return code
[ Pau Espin Pedrol ]
* mgcp_client_vty.c: Fix VTY compatibility with 'mgcpgw bts-base'
-- Harald Welte <laforge@gnumonks.org> Fri, 10 Nov 2017 11:10:23 +0900
osmo-mgw (1.1.0) unstable; urgency=medium
* New upstream release
-- Harald Welte <lafore@gnumonks.org> Sat, 28 Oct 2017 12:48:41 +0200
osmo-mgw (1.0.2) unstable; urgency=low
* First release after major rename.
-- Max Suraev <msuraev@sysmocom.de> Thu, 14 Sep 2017 18:41:05 +0200
osmo-mgw (0.1.0) unstable; urgency=low
* Initial release.

56
debian/control vendored
View File

@@ -9,51 +9,22 @@ Build-Depends: debhelper (>=9),
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/
Homepage: https://osmocom.org/projects/osmo-mgw
Vcs-Git: git://git.osmocom.org/osmo-iuh.git
Vcs-Browser: https://git.osmocom.org/osmo-iuh/
Homepage: https://projects.osmocom.org/projects/osmohnbgw
Package: osmo-mgw
Architecture: any
Multi-Arch: foreign
Depends: libosmo-mgcp1, ${misc:Depends}, ${shlibs:Depends}
Depends: libosmo-legacy-mgcp0, ${misc:Depends}, ${shlibs:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-mgcp1
Section: libs
Package: osmo-mgw-dbg
Section: debug
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: libosmo-mgcp: Osmocom's Media Gateway server library
Package: libosmo-mgcp-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp1 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp: Osmocom's Media Gateway server library
Package: libosmo-mgcp-client2
Section: libs
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: libosmo-mgcp-client-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-mgcp-client2 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-mgcp-client: Osmocom's Media Gateway Control Protocol client utilities
Package: osmo-bsc-mgcp
Architecture: any
Multi-Arch: foreign
Depends: libosmo-legacy-mgcp0, ${misc:Depends}, ${shlibs:Depends}
Description: OsmoBSC-MGCP: Osmocom's Legacy Media Gateway; use osmo-mgw instead.
Depends: osmo-mgw (= ${binary:Version}), ${misc:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-legacy-mgcp0
Section: libs
@@ -61,11 +32,18 @@ Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: libosmo-legacy-mgcp: Osmocom's Legacy Media Gateway server library; use libosmo-mgcp instead.
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-legacy-mgcp-dbg
Section: debug
Architecture: any
Multi-Arch: same
Depends: libosmo-legacy-mgcp0 (= ${binary:Version}), ${misc:Depends}
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks
Package: libosmo-legacy-mgcp-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Depends: libosmo-legacy-mgcp0 (= ${binary:Version}), ${misc:Depends}
Description: libosmo-legacy-mgcp: Osmocom's Legacy Media Gateway server library; use libosmo-mgcp instead.
Description: OsmoMGW: Osmocom's Media Gateway for 2G and 3G circuit-switched mobile networks

2
debian/copyright vendored
View File

@@ -6,7 +6,7 @@ Files: *
Copyright: 2009-2014 On-Waves
2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
2016-2017 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
2016 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
License: AGPL-3.0+
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

View File

@@ -1,4 +1,3 @@
usr/include/osmocom/legacy_mgcp
usr/lib/*/libosmo-legacy-mgcp.so
usr/lib/*/libosmo-legacy-mgcp.a
usr/lib/*/pkgconfig/libosmo-legacy-mgcp.pc
usr/include
usr/lib/*/*.so
usr/lib/*/pkgconfig/*.pc

View File

@@ -1 +1 @@
usr/lib/*/libosmo-legacy-mgcp.so.*
usr/lib/*/*.so.*

View File

@@ -1,4 +0,0 @@
usr/include/osmocom/mgcp_client
usr/lib/*/libosmo-mgcp-client.so
usr/lib/*/libosmo-mgcp-client.a
usr/lib/*/pkgconfig/libosmo-mgcp-client.pc

View File

@@ -1 +0,0 @@
usr/lib/*/libosmo-mgcp-client.so.*

View File

@@ -1,4 +0,0 @@
usr/include/osmocom/mgcp
usr/lib/*/libosmo-mgcp.so
usr/lib/*/libosmo-mgcp.a
usr/lib/*/pkgconfig/libosmo-mgcp.pc

View File

@@ -1 +0,0 @@
usr/lib/*/libosmo-mgcp.so.*

View File

@@ -1 +0,0 @@
usr/bin/osmo-bsc_mgcp

View File

@@ -1 +0,0 @@
../contrib/systemd/osmo-bsc-mgcp.service

View File

@@ -1 +1 @@
usr/bin/osmo-mgw
usr/bin

View File

@@ -1 +0,0 @@
../contrib/systemd/osmo-mgw.service

8
debian/rules vendored
View File

@@ -10,8 +10,6 @@ DEBIAN := $(shell dpkg-parsechangelog | grep '^Version:' | cut -d' ' -f2)
DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1)
VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
CFLAGS += -g
# main packaging script based on dh7 syntax
%:
dh $@ --with autoreconf
@@ -26,11 +24,11 @@ CFLAGS += -g
#override_dh_install:
# dh_install --list-missing -X.la -X.pyc -X.pyo
override_dh_auto_test:
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
override_dh_autoreconf:
echo $(VERSION) > .tarball-version
dh_autoreconf
# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
override_dh_strip:
dh_strip --dbg-package=osmo-mgw-dbg
dh_strip --dbg-package=libosmo-legacy-mgcp-dbg

31
doc/BS11-OML.txt Normal file
View File

@@ -0,0 +1,31 @@
The Siemens BS-11 supports the following additional GSM 12.21 OML operations:
CREATE OBJECT
abis_om_fom_hdr.obj_class can be
A3:
A5: ALCO, BBSIG, CCLK, GPSU, LI, PA
A8: EnvaBTSE
A9: BPORT
the abis_om_obj_inst.trx_nr field indicates the index of object, whereas the
abis_om_fom_hdr.bts_nr indicates the type of the object.
enum abis_bs11_objtype {
BS11_OBJ_ALCO = 0x01,
BS11_OBJ_BBSIG = 0x02, /* obj_class: 0,1 */
BS11_OBJ_TRX1 = 0x03, /* only DEACTIVATE TRX1 */
BS11_OBJ_CCLK = 0x04,
BS11_OBJ_GPSU = 0x06,
BS11_OBJ_LI = 0x07,
BS11_OBJ_PA = 0x09, /* obj_class: 0, 1*/
};
In case of CREATE ENVABTSE, the abis_om_obj_inst.trx_nr indicates the EnvaBTSEx
number.
In case of A9 (CREAETE BPORT), the abis_om_obj_inst.bts_nr indicates which BPORT
shall be used.

25
doc/call-routing.txt Normal file
View File

@@ -0,0 +1,25 @@
Call routing in OpenBSC
Flow of events:
# MO call initiated by MS, CHANNEL RQD, IMMEDIATE ASSIGN
# MS sends CC SETUP message, we assume already on TCH/H FACCH
# OpenBSC does a subscriber lookup based on the target extension
* If a subscriber is found:
# send CALL PROCEEDING message to MO
# page the MT subscriber and ask itI to ask for TCH/H
# once paging completes, we have the TCH/H for the MT end
# send SETUP to MT
# receive CALL CONFIRMED from MT
# set-up the TRAU mux mapping between the E1 subslots for both TCH/H
# receive ALERTING from MT, route ALERTING to MO
# receive CONNECT from MT, confirm to MT with CONNECT_ACK
# send a CONNECT message to MO, receive CONNECT_ACK from MO
* If subscriber is not found:
# send RELEASE COMPLETE with apropriate cause to MO (1: unalloacated 3: no route)
Thoughts about RR/MM:
* we allocate RR/MM entities on demand, when we need them

95
doc/channel_release.txt Normal file
View File

@@ -0,0 +1,95 @@
GSM 04.08 7.1.7 / 9.1.7 RR CHANNEL RELESE
RSL 08.58 3.4 / ? RLL Link Release Request
RSL 08.58 4.6 / 8.4.5 DEACTivate SACCH
* Deactivate SACCH according to Channel Release Proc 04.08
* to be sent after RR CHANNEL RELEASE is sent to MS
RSL 08.58 4.7 / 8.4.14 RF CHANnel RELease
* tells the BTS to release a radio channel
* "when an activated radio channel is no longer needed"
* BTS responds with RF CHANnel RELease ACKnowledge
GSM 04.08 3.4.13: RR connection release procedure
* network sends RR CHANNEL RELEASE to MS on the DCCH
* start T3109
* deactivate SACCH
* MS disconnects main signalling link (by sending DISC)
* all other data links are disconnected by local end link release
* network receives DISC (BTS sends RLL REL IND to BSC)
* stop T3109
* start T3111
* when T3111 times out, the network can reuse the channls
* if T3109 times out, the network deactivates the channels
and can reuse them
* this probably means simply RF CHANnel RELease
== Implementation in OpenBSC ==
There are two possible reasons a gsm_subscriber_connection
will be released. One is a network failure, the other is
the completion of an operation/transaction.
=== Failure ===
The BSC API will call the gsm_04_08.c:gsm0408_clear_request callback
and the MSC part will release all transactions, operations and such
and the channels will be released as error case.
=== Success ===
Every time an 'operation' or 'transaction' is finished msc_release_connection
will be called and it will determine if the gsm_subscriber_connection can
be released.
In case it can be released bsc_api.c:gsm0808_clear will be called
which will release all lchan's associated with the connection. For the
primary channel a SACH Deactivate will be send with the release
reason NORMAL RELEASE.
bsc_api.c:gsm0808_clear
* Release a channel used for handover
* Release the primary lchan with normal release, SACH deactivate
chan_alloc.c:lchan_release(chan, sacch_deactivate, reason)
* Start the release procedure. It is working in steps with callbacks
coming from the abis_rsl.c code.
* Release all SAPI's > 0 as local end (The BTS should send a
REL_CONF a message)
* Send SACH Deactivate on SAPI=0 if required.
* Start T3109 (stop it when the main signalling link is disconnected)
or when the channel released. On timeout start the error handling.
* abis_rsl.c schedules the RSL_MT_RF_CHAN_REL once all SAPI's are
released and after T3111 has timed out or there is an error.
RX of RELease INDication:
* Calls internal rsl_handle_release which might release the RF.
RX of RELease CONFirmation:
* Calls internal rsl_handle_release which might release the RF.
* RX of RF_CHAN_REL_ACK
* call lchan_free()
=== Integration with SMS ===
* RX of CP_ERROR or unimplemented MT
* trigger trans_free() which will msc_release_connection()
* CP TC1* expired while waiting for CP-ACK
* trigger trans_free() which will msc_release_connection()
* RX of RP_ERROR
* trigger trans_free() which will msc_release_connection()
* TX of CP-ACK in MT DELIVER
* trigger trans_free() which will msc_release_connection()
* RX of CP-ACK in MO SUBMIT
* trigger trans_free() which will msc_release_connection()

172
doc/e1-data-model.txt Normal file
View File

@@ -0,0 +1,172 @@
E1 related data model
This data model describes the physical relationship of the individual
parts in the network, it is not the logical/protocol side of the GSM
network.
A BTS is connected to the BSC by some physical link. It could be an actual
E1 link, but it could also be abis-over-IP with a mixture of TCP and RTP/UDP.
To further complicate the fact, multiple BTS can share one such pysical
link. On a single E1 line, we can easily accomodate up to three BTS with
two TRX each.
Thus, it is best for OpenBSC to have some kind of abstraction layer. The BSC's
view of a BTS connected to it. We call this 'bts_link'. A bts_link can be
* all the TCP and UDP streams of a Abis-over-IP BTS
* a set of E1 timeslots for OML, RSL and TRAU connections on a E1 link
* a serial line exclusively used for OML messages (T-Link)
A bts_link can be registered with the OpenBSC core at runtime.
struct trx_link {
struct gsm_bts_trx *trx;
};
struct bts_link {
struct gsm_bts *bts;
struct trx_link trx_links[NUM_TRX];
};
Interface from stack to input core:
======================================================================
int abis_rsl_sendmsg(struct msgb *msg);
send a message through a RSL link to the TRX specified by the caller in
msg->trx.
int abis_rsl_rcvmsg(struct msgb *msg);
receive a message from a RSL link from the TRX specified by the
caller in msg->trx.
int abis_nm_sendmsg(struct msgb *msg);
send a message through a OML link to the BTS specified by the caller in
msg->trx->bts. The caller can just use bts->c0 to get the first TRX
in a BTS. (OML messages are not really sent to a TRX but to the BTS)
int abis_nm_rcvmsg(struct msgb *msg);
receive a message from a OML link from the BTS specified by the caller
in msg->trx->bts. The caller can just use bts->c0 to get the first
TRX in a BTS.
int abis_link_event(int event, void *data);
signal some event (such as layer 1 connect/disconnect) from the
input core to the stack.
int subch_demux_in(mx, const uint8_t *data, int len);
receive 'len' bytes from a given E1 timeslot (TRAU frames)
int subchan_mux_out(mx, uint8_t *data, int len);
obtain 'len' bytes of output data to be sent on E1 timeslot
Intrface by Input Core for Input Plugins
======================================================================
int btslink_register_plugin();
Configuration for the E1 input module
======================================================================
BTS
BTS number
number of TRX
OML link
E1 line number
timeslot number
[subslot number]
SAPI
TEI
for each TRX
RSL link
E1 line number
timeslot number
[subslot number]
SAPI
TEI
for each TS
E1 line number
timeslot number
subslot number
E1 input module data model
======================================================================
enum e1inp_sign_type {
E1INP_SIGN_NONE,
E1INP_SIGN_OML,
E1INP_SIGN_RSL,
};
struct e1inp_sign_link {
/* list of signalling links */
struct llist_head list;
enum e1inp_sign_type type;
/* trx for msg->trx of received msgs */
struct gsm_bts_trx *trx;
/* msgb queue of to-be-transmitted msgs */
struct llist_head tx_list;
/* SAPI and TEI on the E1 TS */
uint8_t sapi;
uint8_t tei;
}
enum e1inp_ts_type {
E1INP_TS_TYPE_NONE,
E1INP_TS_TYPE_SIGN,
E1INP_TS_TYPE_TRAU,
};
/* A timeslot in the E1 interface */
struct e1inp_ts {
enum e1inp_ts_type type;
struct e1inp_line *line;
union {
struct {
struct llist_head sign_links;
} sign;
struct {
/* subchannel demuxer for frames from E1 */
struct subch_demux demux;
/* subchannel muxer for frames to E1 */
struct subch_mux mux;
} trau;
};
union {
struct {
/* mISDN driver has one fd for each ts */
struct osmo_fd;
} misdn;
} driver;
};
struct e1inp_line {
unsigned int num;
char *name;
struct e1inp_ts ts[NR_E1_TS];
char *e1inp_driver;
void *driver_data;
};
/* Call from the Stack: configuration of this TS has changed */
int e1inp_update_ts(struct e1inp_ts *ts);
/* Receive a packet from the E1 driver */
int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
uint8_t tei, uint8_t sapi);
/* Send a packet, callback function in the driver */
int e1driver_tx_ts(struct e1inp_ts *ts, struct msgb *msg)
struct e1inp_driver {
const char *name;
int (*want_write)(struct e1inp_ts *ts);
};

View File

@@ -0,0 +1,105 @@
!
! OsmoBSC (0.9.14+gitr1+3d331c0062bb0c9694dbd4d1eab7adc58138c3ae) configuration saved from vty
!!
password foo
!
!
line vty
no login
!
e1_input
e1_line 0 driver ipa
network
network country code 1
mobile network code 1
short name OsmoBSC
long name OsmoBSC
auth policy closed
location updating reject cause 13
encryption a5 0
neci 1
paging any use tch 0
rrlp mode none
mm info 1
handover 0
handover window rxlev averaging 10
handover window rxqual averaging 1
handover window rxlev neighbor averaging 10
handover power budget interval 6
handover power budget hysteresis 3
handover maximum distance 9999
timer t3101 10
timer t3103 0
timer t3105 0
timer t3107 0
timer t3109 0
timer t3111 0
timer t3113 60
timer t3115 0
timer t3117 0
timer t3119 0
timer t3122 0
timer t3141 0
bts 0
type nanobts
band DCS1800
cell_identity 0
location_area_code 1
training_sequence_code 7
base_station_id_code 63
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
rach tx integer 9
rach max transmission 7
dtx uplink force
dtx downlink
ip.access unit_id 0 0
oml ip.access stream_id 255 line 0
neighbor-list mode manual-si5
neighbor-list add arfcn 100
neighbor-list add arfcn 200
si5 neighbor-list add arfcn 10
si5 neighbor-list add arfcn 20
gprs mode none
trx 0
rf_locked 0
arfcn 871
nominal power 23
max_power_red 20
rsl e1 tei 0
timeslot 0
phys_chan_config CCCH+SDCCH4
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
hopping enabled 0
timeslot 2
phys_chan_config TCH/F
hopping enabled 0
timeslot 3
phys_chan_config TCH/F
hopping enabled 0
timeslot 4
phys_chan_config TCH/F
hopping enabled 0
timeslot 5
phys_chan_config TCH/F
hopping enabled 0
timeslot 6
phys_chan_config TCH/F
hopping enabled 0
timeslot 7
phys_chan_config TCH/F
hopping enabled 0
msc
ip.access rtp-base 4000
timeout-ping 20
timeout-pong 5
dest 192.168.100.11 6666 0
access-list-name msc-list
no access-list-name
bsc
no access-list-name
access-list-name bsc-list

View File

@@ -1,14 +1,19 @@
!
! MGCP configuration example
! MGCP configuration hand edited
! !
password foo
!
line vty
no login
!
mgcp
!local ip 10.23.24.2
!bts ip 10.24.24.1
!bind ip 10.23.24.1
bind port 2427
rtp base 4000
rtp force-ptime 20
sdp audio payload number 98
sdp audio payload name AMR/8000
number endpoints 31
no rtcp-omit
local ip 10.23.24.2
bts ip 10.24.24.1
bind ip 10.23.24.1
bind port 2427
rtp base 4000
rtp force-ptime 20
sdp audio payload number 98
sdp audio payload name AMR/8000
number endpoints 31
no rtcp-omit

View File

@@ -0,0 +1 @@
678012512671923:6:6:

View File

@@ -0,0 +1,13 @@
nat
bsc 0
token lol
location_area_code 1234
description bsc
max-endpoints 32
paging forbidden 0
bsc 1
token wat
location_area_code 5678
description bsc
max-endpoints 32
paging forbidden 0

View File

@@ -0,0 +1,66 @@
!
! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level rll notice
logging level cc notice
logging level mm notice
logging level rr notice
logging level rsl notice
logging level nm info
logging level mncc notice
logging level pag notice
logging level meas notice
logging level sccp notice
logging level msc notice
logging level mgcp notice
logging level ho notice
logging level db notice
logging level ref notice
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level llc debug
logging level sndcp debug
logging level nat notice
logging level ctrl notice
logging level smpp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
mgcp
bind ip 0.0.0.0
bind port 2427
rtp bts-base 4000
rtp net-base 16000
rtp ip-dscp 0
no rtcp-omit
sdp audio-payload number 126
sdp audio-payload name AMR/8000
loop 0
number endpoints 1
call-agent ip 127.0.0.1
rtp transcoder-base 0
transcoder-remote-base 4000
nat
msc ip 127.0.0.1
msc port 5000
timeout auth 2
timeout ping 20
timeout pong 5
ip-dscp 0
bscs-config-file bscs.cfg
access-list bla imsi-allow ^11$

View File

@@ -0,0 +1,44 @@
!
! OsmoGbProxy (UNKNOWN) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
ns
nse 666 nsvci 666
nse 666 remote-role sgsn
! nse 666 encapsulation framerelay-gre
! nse 666 remote-ip 172.16.1.70
! nse 666 fr-dlci 666
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-port 23000
! encapsulation framerelay-gre enabled 1
gbproxy
sgsn nsei 666
core-mobile-country-code 666
core-mobile-network-code 6
core-access-point-name none match-imsi ^666066|^66607
tlli-list max-length 200

View File

@@ -0,0 +1,25 @@
!
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
!!
!
line vty
no login
!
gbproxy
sgsn nsei 101
ns
nse 101 nsvci 101
nse 101 remote-role sgsn
nse 101 encapsulation udp
nse 101 remote-ip 192.168.100.239
nse 101 remote-port 7777
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation framerelay-gre enabled 0
encapsulation framerelay-gre local-ip 0.0.0.0
encapsulation udp local-port 23000

View File

@@ -0,0 +1,90 @@
Here is a simple setup to test GTPHub operations. The IP addresses picked will
work well only on a system that creates local addresses (127.0.0.123) on the
fly (like linux) -- you may pick of course different IP addresses.
Overview of the example setup:
sgsnemu gtphub ggsn
127.0.0.1 <--> 127.0.0.3 127.0.0.4 <--> 127.0.0.2
Prerequisites: openggsn.
Have a local directory where you store config files and from which you launch
the GSNs and the hub (they will store restart counter files in that dir).
In it, have these config files:
ggsn.conf:
# GGSN local address
listen 127.0.0.2
# End User Addresses are picked from this range
net 10.23.42.0/24
pcodns1 8.8.8.8
logfile /tmp/foo
gtphub.conf:
gtphub
bind-to-sgsns 127.0.0.3
bind-to-ggsns 127.0.0.4
ggsn-proxy 127.0.0.2
end
(
You may omit the ggsn-proxy if GRX ares is working, or if you add the GRX
address and GGSN IP address to /etc/hosts something like:
127.0.0.2 internet.mnc070.mcc901.gprs
)
Once the config files are in place, start the programs, in separate terminals.
GGSN and SGSN need to be started with root priviliges to be able to create tun
interfaces. GTPHub may run as unprivileged user.
The LD_LIBRARY_PATH below may be needed if OpenGGSN installed to /usr/local.
1. GGSN:
sudo -s
cd <your-test-dir>
LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/ggsn -f -c ./ggsn.conf
2. GTPHub:
cd <your-test-dir>
path/to/openbsc/openbsc/src/gprs/osmo-gtphub -c gtphub.conf #-e 1 #for DEBUG level
3. SGSN tests:
sudo -s
cd <your-test-dir>
/usr/local/bin/sgsnemu --createif -l 127.0.0.1 -r 127.0.0.3 --imsi 420001214365100 --contexts=3
Add more SGSNs using different IMSIs and local ports (if the same IMSI is used,
the GGSN will reuse TEIs and tunnels will be discarded automatically):
/usr/local/bin/sgsnemu --createif -l 127.0.0.11 -r 127.0.0.3 --imsi 420001214365300 --contexts=3
This shows the basic setup of GTPHub. Testing internet traffic via sgsnemu
still needs some effort to announce a mobile subscriber or the like (I have
used a real BTS, osmo-sgsn and a testing SIM in a web phone, instead).
The core capability of GTPHub is to manage more than two GSNs, e.g. an SGSN
contacting various GGSNs over the single GTPHub link. You would configure the
SGSN to use one fixed GGSN (sending to gtphub) and gtphub will resolve the
GGSNs once it has received the messages. So the SGSN may be behind NAT (add
"sgsn-use-sender" to gtphub.conf) and communicate to various GGSNs over a
single link to gtphub.
I hope this helps to get you going.
Any suggestions/patches are welcome!
~Neels

View File

@@ -0,0 +1,25 @@
!
! Osmocom gtphub configuration
!
! This file is used for VTY tests, referenced by openbsc/osmoappdesc.py
! For the test, try to use most config commands.
!
line vty
no login
gtphub
! Local addresses to listen on and send from, both on one interface.
! The side towards SGSN uses nonstandard ports.
bind-to-sgsns ctrl 127.0.0.1 12123 user 127.0.0.1 12153
! The GGSN side with standard ports.
bind-to-ggsns 127.0.0.1
! Proxy: unconditionally direct all traffic to...
sgsn-proxy 127.0.0.4
! Proxy with nonstandard ports or separate IPs:
ggsn-proxy ctrl 127.0.0.3 2123 user 127.0.0.5 2152
! Add a name server for GGSN resolution
grx-dns-add 192.168.0.1

View File

@@ -0,0 +1,25 @@
!
! Osmocom gtphub configuration
!
line vty
no login
gtphub
! Local addresses to listen on and send from, each on standard ports
! 2123 and 2152. Setting these addresses is mandatory.
bind-to-sgsns 127.0.0.1
bind-to-ggsns 127.0.0.2
! Local nonstandard ports or separate IPs:
!bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223
! Proxy: unconditionally direct all traffic to...
!ggsn-proxy 127.0.0.3
!sgsn-proxy 127.0.0.4
! Proxy with nonstandard ports or separate IPs:
!ggsn-proxy ctrl 127.0.0.3 2123 user 127.0.0.5 2152
! Add a name server for GGSN resolution
!grx-dns-add 192.168.0.1

View File

@@ -1,18 +0,0 @@
!
! MGCP configuration example
!
mgcp
bind ip 127.0.0.1
rtp port-range 4002 16000
rtp bind-ip 10.9.1.122
rtp ip-probing
rtp ip-tos 184
bind port 2427
sdp audio payload number 98
sdp audio payload name GSM
number endpoints 31
loop 0
force-realloc 1
rtcp-omit
rtp-patch ssrc
rtp-patch timestamp

View File

@@ -0,0 +1,19 @@
!
! OsmoMSC configuration saved from vty
!
line vty
no login
!
network
network country code 1
mobile network code 1
short name OsmoMSC
long name OsmoMSC
auth policy closed
location updating reject cause 13
encryption a5 0
rrlp mode none
mm info 1
msc
mgcpgw remote-ip 10.23.24.1
assign-tmsi

View File

@@ -0,0 +1,29 @@
!
! Osmocom SGSN configuration
!
!
line vty
no login
!
sgsn
gtp local-ip 10.23.24.1
ggsn 0 remote-ip 10.23.24.2
ggsn 0 gtp-version 1
auth-policy remote
gsup remote-ip 127.0.0.1
gsup remote-port 4222
!
ns
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 10.23.24.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
!
bssgp
!

54
doc/gsm-hopping.txt Normal file
View File

@@ -0,0 +1,54 @@
according to GSM 05.02:
general parameters from CCCH:
* CA cell allocation of ARFCN's (System Information / BCCH)
* FN: TDMA frame number (t1,t2,t3') in SCH
specific parameters from channel assignment:
* MA: mobile allocation, defines set of ARFCN's, up to 64
* MAIO: index
* HSN: hopping sequence generator number (0..64)
hopping sequence generation (6.2.3):
uint8_t rntable[114] = {
48, 98, 63, 1, 36, 95, 78, 102, 94, 73,
0, 64, 25, 81, 76, 59, 124, 23, 104, 100,
101, 47, 118, 85, 18, 56, 96, 86, 54, 2,
80, 34, 127, 13, 6, 89, 57, 103, 12, 74,
55, 111, 75, 38, 109, 71, 112, 29, 11, 88,
87, 19, 3, 68, 110, 26, 33, 31, 8, 45,
82, 58, 40, 107, 32, 5, 106, 92, 62, 67,
77, 108, 122, 37, 60, 66, 121, 42, 51, 126,
117, 114, 4, 90, 43, 52, 53, 113, 120, 72,
16, 49, 7, 79, 119, 61, 22, 84, 9, 97,
125, 99, 17, 123
};
/* mai=0 represents lowest ARFCN in the MA */
uint8_t hopping_mai(uint8_t hsn, uint32_t fn, uint8_t maio,
uint8_t t1, uint8_t t2, uint8_t t3_)
{
uint8_t mai;
if (hsn == 0) /* cyclic hopping */
mai = (fn + maio) % n;
else {
uint32_t m, m_, t_, s;
m = t2 + rntable[(hsn xor (t1 % 64)) + t3];
m_ = m % (2^NBIN);
t_ = t3 % (2^NBIN);
if (m_ < n then)
s = m_;
else
s = (m_ + t_) % n;
mai = (s + maio) % n;
}
return mai;
}

89
doc/handover.txt Normal file
View File

@@ -0,0 +1,89 @@
Ideas about a handover algorithm
======================================================================
This is mostly based on the results presented in Chapter 8 of "Performance
Enhancements in a Frequency Hopping GSM Network" by Thomas Toftegaard Nielsen
and Joeroen Wigard.
=== Reasons for performing handover ===
Section 2.1.1: Handover used in their CAPACITY simulation:
1) Interference Handover
Average RXLEV is satisfactory high, but average RXQUAL too low indicates
interference to the channel. Handover should be made.
2) Bad Quality
Averaged RXQUAL is lower than a threshold
3) Low Level / Signal Strength
Average RXLEV is lower than a threshold
4) Distance Handover
MS is too far away from a cell (measured by TA)
5) Power budget / Better Cell
RX Level of neighbor cell is at least "HO Margin dB" dB better than the
current serving cell.
=== Ideal parameters for HO algorithm ===
Chapter 8, Section 2.2, Table 24:
Window RXLEV averaging: 10 SACCH frames (no weighting)
Window RXQUAL averaging: 1 SACCH frame (no averaging)
Level Threashold: 1 of the last 1 AV-RXLEV values < -110dBm
Quality Threshold: 3 of the last 4 AV-RXQUAL values >= 5
Interference Threshold: 1 of the last AV-RXLEV > -85 dBm &
3 of the last 4 AV-RXQUAL values >= 5
Power Budget: Level of neighbor cell > 3 dB better
Power Budget Interval: Every 6 SACCH frames (6 seconds ?!?)
Distance Handover: Disabled
Evaluation rule 1: RXLEV of the candidate cell a tleast -104 dBm
Evaluation rule 2: Level of candidate cell > 3dB better own cell
Timer Successful HO: 5 SACCH frames
Timer Unsuccessful HO: 1 SACCH frame
In a non-frequency hopping case, RXQUAL threshold can be decreased to
RXLEV >= 4
When frequency hopping is enabled, the following additional parameters
should be introduced:
* No intra-cell handover
* Use a HO Margin of 2dB
=== Handover Channel Reservation ===
In loaded network, each cell should reserve some channels for handovers,
rather than using all of them for new call establishment. This reduces the
need to drop calls due to failing handovers, at the expense of failing new call
attempts.
=== Dynamic HO Margin ===
The handover margin (hysteresis) should depend on the RXQUAL. Optimal results
were achieved with the following settings:
* RXQUAL <= 4: 9 dB
* RXQUAL == 5: 6 dB
* RXQUAL >= 6: 1 dB
== Actual Handover on a protocol level ==
After the BSC has decided a handover shall be done, it has to
# allocate a channel at the new BTS
# allocate a handover reference
# activate the channel on the BTS side using RSL CHANNEL ACTIVATION,
indicating the HO reference
# BTS responds with CHAN ACT ACK, including GSM frame number
# BSC sends 04.08 HO CMD to MS using old BTS

94
doc/ipa-sccp.txt Normal file
View File

@@ -0,0 +1,94 @@
IPA SCCP message flow in the BSC
February, 2013 Holger Hans Peter Freyther
CONTENTS
1. SCCP inside the IPA header
2. Supported SCCP message types
3. Receiving SCCP messages
4. Sending SCCP messages
1. SCCP inside the IPA header
Many Soft-MSCs implement something that is called SCCP/lite. This means
that SCCP messages are transported inside a small multiplexing protocol
over TCP/IP. This is an alternative to a full SIGTRAN implementation.
The multiplexing protocol is the same as used with the sysmoBTS and the
ip.access nanoBTS. It is a three byte header with two bytes for the length
in network byte order and one byte for the type. The type to be used for
SCCP is 0xFD.
struct ipa_header {
uint16_t length_in_network_order;
uint8_t type;
} __attribute__((packed));
2. Supported SCCP message types
To implement GSM 08.08 only a subset of SCCP messages need to be implemented.
For transporting paging and reset messages SCCP UDT messages are used. For
the connections with a Mobile Station (MS) a SCCP connection is opened. This
means that the SCCP CR, SCCP CC, SCCP CREF, SCCP RLC, SCCP RLSD, SCCP DT1
and SCCP IT messages are supported.
3. Receiving SCCP UDT messages
This is an illustration of the flow of messages. The IPA multiplexing protocol
is used for various protocols. This means there is a central place where the
multiplexing stream terminates. The stream is terminated in the osmo_bsc_msc.c
file and the ipaccess_a_fd_cb method. For SCCP messages the SCCP dispatching
sccp_system_incoming method is called. This function is implemented in the
libosmo-sccp library.
To receive UDT messages osmo_bsc_sccp.c:osmo_bsc_sccp_init is using the
sccp_set_read function to register a callback for UDT messages. The callback
is msc_sccp_read and it is calling bsc_handle_udt that is implemented in the
osmo_bsc_bssap.c. This function will handle the GSM 08.08 BSSAP messages.
Currently only the reset acknowledge and the paging messages are handled.
The BSC currently does not accept incoming SCCP messages and is only opening
SCCP connections to the MSC. When opening a connection the callbacks for state
changes (connection confirmed, released, release complete) are set and a routine
for handling incoming data. This registration is done in the osmo_bsc_sccp.c
file and the bsc_create_new_connection method. The name of the callback is
msc_outgoing_sccp_data and this will call bsc_handle_dt1 that is implemented
in the osmo_bsc_bssap.c file. This will forward the messages to the right
Mobile Station (MS).
4. Sending SCCP messages
There are three parts to sending that will be explained below. The first part
is to send an entire SCCP frame (which includes the GSM 08.08 data) to the
MSC. This is done by first registering the low level sending. sccp_system_init
is called with the function that is responsible for sending a message. The
msc_sccp_write_ipa will call the msc_queue_write function with the data and
the right MSC connection. Below the msc_queue_write the IPA header will be
prepended to the msg and then send to the MSC.
The BSC supports multiple different A-link connections, the decision to pick
the right MSC is done in this method. It is either done via the SCCP connection
or the ctx pointer.
When the BSC is starting a BSS RESET message will be sent to the MSC. The reset
is created in osmo_bsc_msc.c:initialize_if_needed and sccp_write is called with
the GSM 08.08 data and the connection to use. The libosmo-sccp library will
embed it into a SCCP UDT message and call the msc_sccp_write_ipa method.
When a new SCCP connection is to be created the bsc_create_new_connection
in the osmo_bsc_sccp.c file. The sccp_connection_socket method will create
the context for a SCCP connection. The state and data callback will be used
to be notified about data and changes. Once the connection is configured the
bsc_open_connection will be called that will ask the libosmo-sccp library to
create a SCCP CR message using the sccp_connection_connect method. For active
connections the sccp_connection_write method will be called.

22
doc/oml-interface.txt Normal file
View File

@@ -0,0 +1,22 @@
oml interface design notes
problems:
* there is no way how to tag a command sent to the BTS, with the response
having the same tag to identify the originator of the command
* therefore, we can have e.g. both the BSC and the OML interface send a
SET ATTRIBUTE message, where the responses would end up at the wrong
query.
* The BTS has 10s to ACK/NACK a command. We do not run any timers.
the only possible solutions i can imagine:
* have some kind of exclusive locking, where the OML interface gets blocked
from the BSC and is exclusively assigned to the OML console until all commands
of the OML console have terminated. This can either be done explicitly
dynamically or on demand
* use the OML interface synchronously, i.e. always wait for the response from
the BTS before
* unilateral / unsolicited messages need to be broadcasted to both the BSC and
the OML console

View File

@@ -0,0 +1,33 @@
digraph G {
net [label="gsm_network"]
bts [label="gsm_bts"]
trx [label="gsm_bts_trx"]
ts [label="gsm_bts_trx_ts"]
lchan [label="gsm_lchan"]
sub [label="gsm_subscriber"]
subcon [label="gsm_subscriber_conn"]
sccpcon [label="osmo_bsc_sccp_con"]
subgrp [label="gsm_subscriber_group"]
net -> bts
bts -> trx
trx -> ts
ts -> lchan
lchan -> ts
ts -> trx
trx -> bts
bts -> net
lchan -> subcon
subcon -> sub
subcon -> sccpcon
subcon -> lchan
subcon -> lchan [label="ho_lchan"]
subcon -> bts
subcon -> lchan [label="secondary_lchan"]
sub -> subgrp
subgrp -> net
}

48
doc/paging.txt Normal file
View File

@@ -0,0 +1,48 @@
GSM Paging implementation in OpenBSC
== Code structure ==
The code is implemented in the libbsc/paging.c file. The external
interface is documented/specified in the include/openbsc/paging.h
header file. The code is used by the NITB and BSC application.
== Implementation ==
Paging can be initiated in two ways. The standard way is to page by
LAC. Each BTS has its own list/queue of outstanding paging operation.
When a subscriber is paged one "struct paging_request" per BTS will
be allocated and added to the tail of the list. The BTS is supposed
to be configured to not repeat the paging.
A paging_request will remain in the queue until a paging response or at
the expiry of the T3113. Every 500 milliseconds a RSL paging command is
send to the BTS. The 500 milliseconds is a throttling to not crash the
ip.access nanoBTS. Once one paging_request has been handled it will be
put at the end of the queue/list and the available slots for the BTS
will be decreased.
The available slots will be updated based on the paging load information
element of the CCCH Load indication. If no paging slots are considered
to be available and no load indication is sent a timer is started. The
current timeout is 500 milliseconds and at the expiry of the timer the
available slots will be set to 20.
OpenBSC has the " paging free <-1-1024>" configuration option. In case
there are less free channels than required no paging request will be
sent to the BTS. Instead it will be attempted to send the paging request
at the next timeout (500 milliseconds).
== Limitation ==
The paging throughput could be higher but this has lead to crashes on the
ip.access nanoBTS in the past.
== Configuration ==
=== ip.access nanoBTS ===
The current CCCH Load indication threshold is 10% and the period is 1 second.
The code can be found inside the src/libbsc/bts_ipaccess_nanobts.c inside the
nanobts_attr_bts array.

View File

@@ -92,8 +92,8 @@ fi
if test -n "$v"
then
: # use $v
elif test -d ./.git \
&& v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
elif
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|| git describe --abbrev=4 HEAD 2>/dev/null` \
&& case $v in
[0-9]*) ;;

View File

@@ -1,15 +1,6 @@
SUBDIRS = \
osmocom \
$(NULL)
nobase_include_HEADERS = \
osmocom/legacy_mgcp/mgcp.h \
osmocom/legacy_mgcp/mgcp_internal.h \
osmocom/legacy_mgcp/mgcpgw_client.h \
osmocom/legacy_mgcp/osmux.h \
osmocom/mgcp_client/mgcp_client.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)

View File

@@ -1,5 +1,3 @@
SUBDIRS = \
legacy_mgcp \
mgcp_client \
mgcp \
$(NULL)

View File

@@ -177,6 +177,13 @@ enum mgcp_connection_mode {
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
};
extern const struct value_string mgcp_connection_mode_strs[];
static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
{
return get_value_string(mgcp_connection_mode_strs, mode);
}
struct mgcp_config {
int source_port;
char *local_ip;

View File

@@ -64,7 +64,7 @@ struct mgcp_rtp_state {
uint32_t stats_jitter;
int32_t stats_transit;
int stats_cycles;
bool patched_first_rtp_payload; /* FIXME: drop this, see OS#2459 */
bool patched_first_rtp_payload;
};
struct mgcp_rtp_codec {

View File

@@ -0,0 +1,73 @@
#pragma once
#include <stdint.h>
#define MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
#define MGCPGW_CLIENT_LOCAL_PORT_DEFAULT 0
#define MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCPGW_CLIENT_REMOTE_PORT_DEFAULT 2427
struct msgb;
struct vty;
struct mgcpgw_client;
struct mgcpgw_client_conf {
const char *local_addr;
int local_port;
const char *remote_addr;
int remote_port;
uint16_t first_endpoint;
uint16_t last_endpoint;
uint16_t bts_base;
};
typedef unsigned int mgcp_trans_id_t;
struct mgcp_response_head {
int response_code;
mgcp_trans_id_t trans_id;
const char *comment;
};
struct mgcp_response {
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
};
void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf);
void mgcpgw_client_vty_init(void *talloc_ctx, int node, struct mgcpgw_client_conf *conf);
int mgcpgw_client_config_write(struct vty *vty, const char *indent);
struct mgcpgw_client_conf *mgcpgw_client_conf_actual(struct mgcpgw_client *mgcp);
struct mgcpgw_client *mgcpgw_client_init(void *ctx,
struct mgcpgw_client_conf *conf);
int mgcpgw_client_connect(struct mgcpgw_client *mgcp);
const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp);
uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp);
uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp);
int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client);
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
int mgcp_response_parse_params(struct mgcp_response *r);
int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
enum mgcp_connection_mode;
struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode);
struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode);
struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
unsigned int call_id);

View File

@@ -1,11 +1,9 @@
#pragma once
#include <osmocom/core/write_queue.h>
#define MSGB_CB_MGCP_TRANS_ID 0
struct mgcp_client {
struct mgcp_client_conf actual;
struct mgcpgw_client {
struct mgcpgw_client_conf actual;
uint32_t remote_addr;
struct osmo_wqueue wq;
mgcp_trans_id_t next_trans_id;
@@ -26,10 +24,10 @@ struct mgcp_response_pending {
void *priv;
};
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg);
int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg);
struct mgcp_response_pending * mgcp_client_pending_add(
struct mgcp_client *mgcp,
struct mgcp_response_pending * mgcpgw_client_pending_add(
struct mgcpgw_client *mgcp,
mgcp_trans_id_t trans_id,
mgcp_response_cb_t response_cb,
void *priv);

View File

@@ -11,7 +11,8 @@ enum {
};
int osmux_init(int role, struct mgcp_config *cfg);
int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port);
int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role,
struct in_addr *addr, uint16_t port);
void osmux_disable_endpoint(struct mgcp_endpoint *endp);
void osmux_allocate_cid(struct mgcp_endpoint *endp);
void osmux_release_cid(struct mgcp_endpoint *endp);

View File

@@ -16,7 +16,7 @@ extern struct cmd_element cfg_description_cmd;
extern struct cmd_element cfg_no_description_cmd;
enum mgcp_vty_node {
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
MGCP_NODE,
TRUNK_NODE,
};

View File

@@ -1,9 +0,0 @@
noinst_HEADERS = \
vty.h \
mgcp_msg.h \
mgcp_conn.h \
mgcp_stat.h \
mgcp_ep.h \
mgcp_sdp.h \
debug.h \
$(NULL)

View File

@@ -1,35 +0,0 @@
/* (C) 2017 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/>.
*
*/
#pragma once
#include <stdio.h>
#include <osmocom/core/linuxlist.h>
#define DEBUG
#include <osmocom/core/logging.h>
/* Debug Areas of the code */
enum {
DRTP,
Debug_LastEntry,
};
extern const struct log_info log_info;

View File

@@ -1,237 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/*
* (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 <osmocom/core/msgb.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/logging.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define RTP_PORT_DEFAULT_RANGE_START 16002
#define RTP_PORT_DEFAULT_RANGE_END RTP_PORT_DEFAULT_RANGE_START + 64
/*
* Handling of MGCP Endpoints and the MGCP Config
*/
struct mgcp_endpoint;
struct mgcp_config;
struct mgcp_trunk_config;
struct mgcp_rtp_end;
#define MGCP_ENDP_CRCX 1
#define MGCP_ENDP_DLCX 2
#define MGCP_ENDP_MDCX 3
/*
* what to do with the msg?
* - continue as usual?
* - reject and send a failure code?
* - defer? do not send anything
*/
#define MGCP_POLICY_CONT 4
#define MGCP_POLICY_REJECT 5
#define MGCP_POLICY_DEFER 6
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);
/**
* Return:
* < 0 in case no audio was processed
* >= 0 in case audio was processed. The remaining payload
* length will be returned.
*/
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct mgcp_rtp_end *src_end);
struct mgcp_conn_rtp;
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
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 {
/* addr or NULL to fall-back to default */
char *bind_addr;
/* dynamically allocated */
int range_start;
int range_end;
int last_port;
/* set to true to enable automatic probing
* of the local bind IP-Address, bind_addr
* (or its fall back) is used when automatic
* probing fails */
bool bind_addr_probe;
};
/* There are up to three modes in which the keep-alive dummy packet can be
* sent. The beviour is controlled viw the keepalive_interval member of the
* trunk config. If that member is set to 0 (MGCP_KEEPALIVE_NEVER) no dummy-
* packet is sent at all and the timer that sends regular dummy packets
* is no longer scheduled. If the keepalive_interval is set to -1, only
* one dummy packet is sent when an CRCX or an MDCX is performed. No timer
* is scheduled. For all vales greater 0, the a timer is scheduled and the
* value is used as interval. See also mgcp_keepalive_timer_cb(),
* handle_modify_con(), and handle_create_con() */
#define MGCP_KEEPALIVE_ONCE (-1)
#define MGCP_KEEPALIVE_NEVER 0
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;
};
enum mgcp_role {
MGCP_BSC = 0,
MGCP_BSC_NAT,
};
struct mgcp_config {
int source_port;
char *local_ip;
char *source_addr;
char *call_agent_addr;
/* RTP processing */
mgcp_processing rtp_processing_cb;
mgcp_processing_setup setup_rtp_processing_cb;
mgcp_get_format get_net_downlink_format_cb;
struct osmo_wqueue gw_fd;
struct mgcp_port_range net_ports;
int endp_dscp;
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;
uint32_t last_call_id;
/* trunk handling */
struct mgcp_trunk_config trunk;
struct llist_head trunks;
enum mgcp_role role;
/* osmux translator: 0 means disabled, 1 means enabled */
int osmux;
/* addr to bind the server to */
char *osmux_addr;
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
* the osmux socket is already initialized.
*/
int osmux_init;
/* osmux batch factor: from 1 to 4 maximum */
int osmux_batch;
/* osmux batch size (in bytes) */
int osmux_batch_size;
/* osmux port */
uint16_t osmux_port;
/* Pad circuit with dummy messages until we see the first voice
* message.
*/
uint16_t osmux_dummy;
};
/* config management */
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);
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
void mgcp_release_endp(struct mgcp_endpoint *endp);
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
/*
* format helper functions
*/
struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg);
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
int mgcp_send_reset_all(struct mgcp_config *cfg);
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);

View File

@@ -1,75 +0,0 @@
/* MGCP common implementations.
* These are used in libosmo-mgcp as well as libosmo-mgcp-client.
* To avoid interdependency, these are implemented in .h file only. */
/*
* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* (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/>.
*
*/
/* Two copies of this file are kept in osmocom/mgcp/ and osmocom/mgcp_client/.
* Since both are by definition identical, use the old header exclusion ifdefs
* instead of '#pragma once' to avoid including both of these files.
* Though at the time of writing there are no such users, this allows including
* both libosmo-mgcp and libosmo-mgcp-client headers in the same file. */
#ifndef OSMO_MGCP_COMMON_H
#define OSMO_MGCP_COMMON_H
#include <string.h>
#include <errno.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#define for_each_non_empty_line(line, save) \
for (line = strtok_r(NULL, "\r\n", &save); line; \
line = strtok_r(NULL, "\r\n", &save))
enum mgcp_connection_mode {
MGCP_CONN_NONE = 0,
MGCP_CONN_RECV_ONLY = 1,
MGCP_CONN_SEND_ONLY = 2,
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
};
/* Ensure that the msg->l2h is NUL terminated. */
static inline int mgcp_msg_terminate_nul(struct msgb *msg)
{
unsigned char *tail = msg->l2h + msgb_l2len(msg); /* char after l2 data */
if (tail[-1] == '\0')
/* nothing to do */;
else if (msgb_tailroom(msg) > 0)
tail[0] = '\0';
else if (tail[-1] == '\r' || tail[-1] == '\n')
tail[-1] = '\0';
else {
LOGP(DLMGCP, LOGL_ERROR, "Cannot NUL terminate MGCP message: "
"Length: %d, Buffer size: %d\n",
msgb_l2len(msg), msg->data_len);
return -ENOTSUP;
}
return 0;
}
/* String length of Connection Identifiers
* (see also RFC3435 2.1.3.2 Names of Connections) */
#define MGCP_CONN_ID_LENGTH 32+1
#endif

View File

@@ -1,39 +0,0 @@
/* Message connection list handling */
/*
* (C) 2017 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/>.
*
*/
#pragma once
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/core/linuxlist.h>
#include <inttypes.h>
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);
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
const char *id);
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id);
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);

View File

@@ -1,50 +0,0 @@
/* Endpoint types */
/*
* (C) 2017 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/>.
*
*/
#pragma once
struct sockaddr_in;
struct mgcp_conn;
/* Callback type for RTP dispatcher functions
(e.g mgcp_dispatch_rtp_bridge_cb, see below) */
typedef int (*mgcp_dispatch_rtp_cb) (int proto, struct sockaddr_in * addr,
char *buf, unsigned int buf_size,
struct mgcp_conn * conn);
/*! MGCP endpoint properties */
struct mgcp_endpoint_type {
/*!< maximum number of connections */
int max_conns;
/*!< callback that defines how to dispatch incoming RTP data */
mgcp_dispatch_rtp_cb dispatch_rtp_cb;
};
/*! MGCP endpoint typeset */
struct mgcp_endpoint_typeset {
struct mgcp_endpoint_type rtp;
};
/*! static MGCP endpoint typeset (pre-initalized, read-only) */
extern const struct mgcp_endpoint_typeset ep_typeset;

View File

@@ -1,323 +0,0 @@
/* MGCP Private Data */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <string.h>
#include <inttypes.h>
#include <osmocom/core/select.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/core/linuxlist.h>
#define CI_UNUSED 0
/* FIXME: This this is only needed to compile the currently
* broken OSMUX support. Remove when fixed */
#define CONN_ID_BTS "0"
#define CONN_ID_NET "1"
enum mgcp_trunk_type {
MGCP_TRUNK_VIRTUAL,
MGCP_TRUNK_E1,
};
struct mgcp_rtp_stream_state {
uint32_t ssrc;
uint16_t last_seq;
uint32_t last_timestamp;
uint32_t err_ts_counter;
int32_t last_tsdelta;
uint32_t last_arrival_time;
};
struct mgcp_rtp_state {
int initialized;
int patch_ssrc;
uint32_t orig_ssrc;
int seq_offset;
int32_t timestamp_offset;
uint32_t packet_duration;
struct mgcp_rtp_stream_state in_stream;
struct mgcp_rtp_stream_state out_stream;
/* jitter and packet loss calculation */
int stats_initialized;
uint16_t stats_base_seq;
uint16_t stats_max_seq;
uint32_t stats_ssrc;
uint32_t stats_jitter;
int32_t stats_transit;
int stats_cycles;
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;
};
struct mgcp_rtp_end {
/* statistics */
unsigned int packets_rx;
unsigned int octets_rx;
unsigned int packets_tx;
unsigned int octets_tx;
unsigned int dropped_packets;
struct in_addr addr;
/* in network byte order */
int rtp_port, rtcp_port;
/* audio codec information */
struct mgcp_rtp_codec codec;
struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */
/* per endpoint data */
int frames_per_packet;
uint32_t packet_duration_ms;
char *fmtp_extra;
int output_enabled;
int force_output_ptime;
/* RTP patching */
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
int force_aligned_timing;
void *rtp_process_data;
/* Each end has a separate socket for RTP and RTCP */
struct osmo_fd rtp;
struct osmo_fd rtcp;
int local_port;
};
struct mgcp_rtp_tap {
int enabled;
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 */
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;
};
/*! 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 conntion */
char id[MGCP_CONN_ID_LENGTH];
/*!< 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;
struct mgcp_endpoint {
char *callid;
struct mgcp_lco local_options;
struct llist_head conns;
/* backpointer */
struct mgcp_config *cfg;
struct mgcp_trunk_config *tcfg;
const struct mgcp_endpoint_type *type;
/* fields for re-transmission */
char *last_trans;
char *last_response;
};
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
/**
* Internal structure while parsing a request
*/
struct mgcp_parse_data {
struct mgcp_config *cfg;
struct mgcp_endpoint *endp;
char *trans;
char *save;
int found;
};
int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
char *buf, int rc, struct mgcp_conn_rtp *conn_src,
struct mgcp_conn_rtp *conn_dst);
int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn);
int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
unsigned int buf_size, struct mgcp_conn *conn);
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);
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_rtp_end *dst_end,
struct mgcp_rtp_end *src_end);
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);

View File

@@ -1,56 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* Message parser/generator utilities */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2017 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/>.
*
*/
#pragma once
#include <stdint.h>
struct mgcp_conn;
struct mgcp_parse_data;
struct mgcp_endpoint;
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble);
int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp,
struct mgcp_conn *conn);
int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data);
int mgcp_parse_osmux_cid(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);
int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id);
char *mgcp_strline(char *str, char **saveptr);
#define for_each_line(line, save)\
for (line = mgcp_strline(NULL, &save); line;\
line = mgcp_strline(NULL, &save))
#define for_each_non_empty_line(line, save)\
for (line = strtok_r(NULL, "\r\n", &save); line;\
line = strtok_r(NULL, "\r\n", &save))

View File

@@ -1,35 +0,0 @@
/*
* SDP generation and parsing
*
* (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2014 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 <osmocom/mgcp/mgcp_sdp.h>
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn,
struct mgcp_parse_data *p);
int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
int payload_type, const char *audio_name);
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
const char *addr);

View File

@@ -1,37 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* The statistics generator */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2017 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/>.
*
*/
#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);
/* Exposed for test purposes only, do not use actively */
void calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
uint32_t *expected, int *loss);
/* Exposed for test purposes only, do not use actively */
uint32_t calc_jitter(struct mgcp_rtp_state *);

View File

@@ -1,38 +0,0 @@
#pragma once
#include <osmocom/netif/osmux.h>
struct mgcp_conn_rtp;
#define OSMUX_PORT 1984
enum {
OSMUX_ROLE_BSC = 0,
OSMUX_ROLE_BSC_NAT,
};
int osmux_init(int role, struct mgcp_config *cfg);
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
struct 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);
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_STATE_NEGOTIATING,
OSMUX_STATE_ACTIVATING,
OSMUX_STATE_ENABLED,
};
enum osmux_usage {
OSMUX_USAGE_OFF = 0,
OSMUX_USAGE_ON = 1,
OSMUX_USAGE_ONLY = 2,
};

View File

@@ -1,31 +0,0 @@
#ifndef OPENBSC_VTY_H
#define OPENBSC_VTY_H
#include <osmocom/vty/vty.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/command.h>
struct gsm_network;
struct vty;
void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
extern struct cmd_element cfg_description_cmd;
extern struct cmd_element cfg_no_description_cmd;
enum mgcp_vty_node {
MGCP_NODE = _LAST_OSMOVTY_NODE + 1,
TRUNK_NODE,
};
struct log_info;
int bsc_vty_init(struct gsm_network *network);
int bsc_vty_init_extra(void);
void msc_vty_init(struct gsm_network *msc_network);
struct gsm_network *gsmnet_from_vty(struct vty *vty);
#endif

View File

@@ -1,13 +0,0 @@
BUILT_SOURCES = \
mgcp_common.h \
$(NULL)
noinst_HEADERS = \
mgcp_client_internal.h \
$(NULL)
mgcp_common.h: $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h
echo -e "/*\n\n DO NOT EDIT THIS FILE!\n THIS IS OVERWRITTEN DURING BUILD\n This is an automatic copy of <osmocom/mgcp/mgcp_common.h>\n\n */" > mgcp_common.h
cat $(top_srcdir)/include/osmocom/mgcp/mgcp_common.h >> mgcp_common.h
CLEANFILES = mgcp_common.h

View File

@@ -1,121 +0,0 @@
#pragma once
#include <stdint.h>
#include <arpa/inet.h>
#include <osmocom/mgcp_client/mgcp_common.h>
#define MGCP_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
#define MGCP_CLIENT_LOCAL_PORT_DEFAULT 0
#define MGCP_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
#define MGCP_CLIENT_REMOTE_PORT_DEFAULT 2427
struct msgb;
struct vty;
struct mgcp_client;
struct mgcp_client_conf {
const char *local_addr;
int local_port;
const char *remote_addr;
int remote_port;
uint16_t first_endpoint;
uint16_t last_endpoint;
uint16_t bts_base;
};
typedef unsigned int mgcp_trans_id_t;
struct mgcp_response_head {
int response_code;
mgcp_trans_id_t trans_id;
const char *comment;
char conn_id[MGCP_CONN_ID_LENGTH];
};
struct mgcp_response {
char *body;
struct mgcp_response_head head;
uint16_t audio_port;
char audio_ip[INET_ADDRSTRLEN];
};
enum mgcp_verb {
MGCP_VERB_CRCX,
MGCP_VERB_MDCX,
MGCP_VERB_DLCX,
MGCP_VERB_AUEP,
MGCP_VERB_RSIP,
};
#define MGCP_MSG_PRESENCE_ENDPOINT 0x0001
#define MGCP_MSG_PRESENCE_CALL_ID 0x0002
#define MGCP_MSG_PRESENCE_CONN_ID 0x0004
#define MGCP_MSG_PRESENCE_AUDIO_IP 0x0008
#define MGCP_MSG_PRESENCE_AUDIO_PORT 0x0010
#define MGCP_MSG_PRESENCE_CONN_MODE 0x0020
/* See also RFC3435 section 3.2.1.3 */
#define MGCP_ENDPOINT_MAXLEN (255*2+1+1)
struct mgcp_msg {
enum mgcp_verb verb;
/* See MGCP_MSG_PRESENCE_* constants */
uint32_t presence;
char endpoint[MGCP_ENDPOINT_MAXLEN];
unsigned int call_id;
char *conn_id;
uint16_t audio_port;
char *audio_ip;
enum mgcp_connection_mode conn_mode;
};
void mgcp_client_conf_init(struct mgcp_client_conf *conf);
void mgcp_client_vty_init(void *talloc_ctx, int node, struct mgcp_client_conf *conf);
int mgcp_client_config_write(struct vty *vty, const char *indent);
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);
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);
int mgcp_client_next_endpoint(struct mgcp_client *client);
void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client);
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
int mgcp_response_parse_params(struct mgcp_response *r);
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv);
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id);
enum mgcp_connection_mode;
struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
unsigned int call_id)
OSMO_DEPRECATED("Use mgcp_msg_gen() instead");
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg);
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg);
extern const struct value_string mgcp_client_connection_mode_strs[];
static inline const char *mgcp_client_cmode_name(enum mgcp_connection_mode mode)
{
return get_value_string(mgcp_client_connection_mode_strs, mode);
}

View File

@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Osmocom Media Gateway Control Protocol Client library
Description: C Utility Library
Version: @VERSION@
Libs: -L${libdir} -losmo-mgcp-client
Cflags: -I${includedir}/

View File

@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: Osmocom Media Gateway Control Protocol library
Description: C Utility Library
Version: @VERSION@
Libs: -L${libdir} -losmo-mgcp
Cflags: -I${includedir}/

View File

@@ -16,15 +16,13 @@
app_configs = {
"osmo-mgw": ["doc/examples/osmo-mgw/osmo-mgw.cfg"],
"osmo-bsc_mgcp": ["doc/examples/osmo-bsc_mgcp/mgcp.cfg"],
"mgcp": ["doc/examples/osmo-bsc_mgcp/mgcp.cfg"],
}
apps = [(4243, "src/osmo-mgw/osmo-mgw", "OsmoMGW", "osmo-mgw"),
(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "OpenBSC MGCP", "osmo-bsc_mgcp"),
apps = [(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "OpenBSC MGCP", "mgcp"),
]
vty_command = ["./src/osmo-mgw/osmo-mgw", "-c",
"doc/examples/osmo-mgw/osmo-mgw.cfg"]
vty_command = ["./src/osmo-bsc_mgcp/osmo-bsc_mgcp", "-c",
"doc/examples/osmo-bsc_mgcp/osmo-bsc_mgcp.cfg"]
vty_app = apps[0]

View File

@@ -22,12 +22,9 @@ AM_LDFLAGS = \
# Libraries
SUBDIRS = \
libosmo-legacy-mgcp \
libosmo-mgcp-client \
libosmo-mgcp \
$(NULL)
# Programs
SUBDIRS += \
osmo-bsc_mgcp \
osmo-mgw \
$(NULL)

View File

@@ -15,15 +15,15 @@ AM_CFLAGS = \
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(COVERAGE_LDFLAGS) \
$(LIBBCG729_LIBS) \
$(LIBRARY_GSM) \
$(NULL)
# 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!
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool
# documentation before making any modification
LEGACY_MGCP_LIBVERSION=0:0:0
lib_LTLIBRARIES = \
@@ -41,6 +41,8 @@ libosmo_legacy_mgcp_la_SOURCES = \
mgcp_vty.c \
mgcp_osmux.c \
mgcp_sdp.c \
mgcpgw_client.c \
mgcpgw_client_vty.c \
$(NULL)
if BUILD_MGCP_TRANSCODING
libosmo_legacy_mgcp_la_SOURCES += \

View File

@@ -667,16 +667,10 @@ int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx],
buf, len);
/* FIXME: HACK HACK HACK. See OS#2459.
* The ip.access nano3G needs the first RTP payload's first two bytes to read hex
* 'e400', or it will reject the RAB assignment. It seems to not harm other femto
* cells (as long as we patch only the first RTP payload in each stream).
*/
if (tap_idx == MGCP_TAP_BTS_OUT
&& !rtp_state->patched_first_rtp_payload) {
uint8_t *data = (uint8_t*)&buf[12];
data[0] = 0xe4;
data[1] = 0x00;
osmo_hexparse("e400", data, 2);
rtp_state->patched_first_rtp_payload = true;
}

View File

@@ -340,7 +340,8 @@ static int osmux_handle_dummy(struct mgcp_config *cfg, struct sockaddr_in *addr,
if (endp->osmux.state == OSMUX_STATE_ENABLED)
goto out;
if (osmux_enable_endpoint(endp, &addr->sin_addr, addr->sin_port) < 0 ) {
if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC_NAT,
&addr->sin_addr, addr->sin_port) < 0 ){
LOGP(DLMGCP, LOGL_ERROR,
"Could not enable osmux in endpoint %d\n",
ENDPOINT_NUMBER(endp));
@@ -432,7 +433,8 @@ int osmux_init(int role, struct mgcp_config *cfg)
return 0;
}
int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port)
int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role,
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
@@ -520,7 +522,8 @@ int osmux_send_dummy(struct mgcp_endpoint *endp)
return 0;
if (endp->osmux.state == OSMUX_STATE_ACTIVATING) {
if (osmux_enable_endpoint(endp, &endp->net_end.addr,
if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC,
&endp->net_end.addr,
htons(endp->cfg->osmux_port)) < 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Could not activate osmux in endpoint %d\n",

View File

@@ -172,7 +172,6 @@ static struct msgb *do_retransmission(const struct mgcp_endpoint *endp)
msg->l2h = msgb_put(msg, strlen(endp->last_response));
memcpy(msg->l2h, endp->last_response, msgb_l2len(msg));
display_mgcp_message(msg->l2h, msgb_l2len(msg), "Retransmitted response");
return msg;
}
@@ -318,12 +317,10 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
if (!addr)
addr = mgcp_net_src_addr(endp);
if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) {
if (endp->osmux.state == OSMUX_STATE_NEGOTIATING)
sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid);
endp->osmux.state = OSMUX_STATE_ACTIVATING;
} else {
else
osmux_extension[0] = '\0';
}
len = snprintf(sdp_record, sizeof(sdp_record),
"I: %u%s\n\n", endp->ci, osmux_extension);
@@ -372,8 +369,8 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
display_mgcp_message(msg->l2h, msgb_l2len(msg), "Received message");
/* attempt to treat it as a response */
if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
/* attempt to treat it as a response */
if (sscanf((const char *)&msg->l2h[0], "%3d %*s", &code) == 1) {
LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
return NULL;
}

View File

@@ -591,16 +591,6 @@ DEFUN(cfg_mgcp_loop,
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_force_realloc,
cfg_mgcp_force_realloc_cmd,
"force-realloc (0|1)",
"Force endpoint reallocation when the endpoint is still seized\n"
"Don't force reallocation\n" "force reallocation\n")
{
g_cfg->trunk.force_realloc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_number_endp,
cfg_mgcp_number_endp_cmd,
"number endpoints <0-65534>",
@@ -813,10 +803,9 @@ static int config_write_trunk(struct vty *vty)
trunk->keepalive_interval, VTY_NEWLINE);
else
vty_out(vty, " no rtp keep-alive%s", VTY_NEWLINE);
vty_out(vty, " loop %d%s",
trunk->audio_loop, VTY_NEWLINE);
vty_out(vty, " force-realloc %d%s",
trunk->force_realloc, VTY_NEWLINE);
if (trunk->omit_rtcp)
vty_out(vty, " rtcp-omit%s", VTY_NEWLINE);
else
@@ -1356,6 +1345,7 @@ int mgcp_vty_init(void)
install_element(CONFIG_NODE, &cfg_mgcp_cmd);
install_node(&mgcp_node, config_write_mgcp);
vty_install_default(MGCP_NODE);
install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
@@ -1389,7 +1379,6 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd_old);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd_old);
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
install_element(MGCP_NODE, &cfg_mgcp_force_realloc_cmd);
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_omit_rtcp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_no_omit_rtcp_cmd);
@@ -1415,6 +1404,7 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
install_node(&trunk_node, config_write_trunk);
vty_install_default(TRUNK_NODE);
install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);

View File

@@ -23,11 +23,11 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/byteswap.h>
#include <osmocom/core/socket.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/mgcp_client/mgcp_client_internal.h>
#include <osmocom/legacy_mgcp/mgcpgw_client.h>
#include <osmocom/legacy_mgcp/mgcp.h>
#include <osmocom/legacy_mgcp/mgcp_internal.h>
#include <osmocom/legacy_mgcp/mgcpgw_client_internal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -36,10 +36,10 @@
#include <unistd.h>
#include <string.h>
void mgcp_client_conf_init(struct mgcp_client_conf *conf)
void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf)
{
/* NULL and -1 default to MGCP_CLIENT_*_DEFAULT values */
*conf = (struct mgcp_client_conf){
/* NULL and -1 default to MGCPGW_CLIENT_*_DEFAULT values */
*conf = (struct mgcpgw_client_conf){
.local_addr = NULL,
.local_port = -1,
.remote_addr = NULL,
@@ -51,7 +51,7 @@ void mgcp_client_conf_init(struct mgcp_client_conf *conf)
}
/* Test if a given endpoint id is currently in use */
static bool endpoint_in_use(uint16_t id, struct mgcp_client *client)
static bool endpoint_in_use(uint16_t id, struct mgcpgw_client *client)
{
struct mgcp_inuse_endpoint *endpoint;
llist_for_each_entry(endpoint, &client->inuse_endpoints, entry) {
@@ -63,7 +63,7 @@ static bool endpoint_in_use(uint16_t id, struct mgcp_client *client)
}
/* Find and seize an unsused endpoint id */
int mgcp_client_next_endpoint(struct mgcp_client *client)
int mgcpgw_client_next_endpoint(struct mgcpgw_client *client)
{
int i;
uint16_t first_endpoint = client->actual.first_endpoint;
@@ -96,7 +96,7 @@ int mgcp_client_next_endpoint(struct mgcp_client *client)
}
/* Release a seized endpoint id to make it available again for other calls */
void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client)
void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client)
{
struct mgcp_inuse_endpoint *endpoint;
struct mgcp_inuse_endpoint *endpoint_tmp;
@@ -108,9 +108,9 @@ void mgcp_client_release_endpoint(uint16_t id, struct mgcp_client *client)
}
}
static void mgcp_client_handle_response(struct mgcp_client *mgcp,
struct mgcp_response_pending *pending,
struct mgcp_response *response)
static void mgcpgw_client_handle_response(struct mgcpgw_client *mgcp,
struct mgcp_response_pending *pending,
struct mgcp_response *response)
{
if (!pending) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -134,7 +134,7 @@ static int mgcp_response_parse_head(struct mgcp_response *r, struct msgb *msg)
r->body = (char *)msg->data;
if (sscanf(r->body, "%3d %u %n",
if (sscanf(r->body, "%3d %u %n",
&r->head.response_code, &r->head.trans_id,
&comment_pos) != 2)
goto response_parse_failure;
@@ -175,9 +175,9 @@ static bool mgcp_line_is_valid(const char *line)
}
/* Parse a line like "m=audio 16002 RTP/AVP 98" */
static int mgcp_parse_audio_port(struct mgcp_response *r, const char *line)
static int mgcp_parse_audio(struct mgcp_response *r, const char *line)
{
if (sscanf(line, "m=audio %hu",
if (sscanf(line, "m=audio %hu",
&r->audio_port) != 1)
goto response_parse_failure;
@@ -185,34 +185,7 @@ static int mgcp_parse_audio_port(struct mgcp_response *r, const char *line)
response_parse_failure:
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse MGCP response header (audio port)\n");
return -EINVAL;
}
/* Parse a line like "c=IN IP4 10.11.12.13" */
static int mgcp_parse_audio_ip(struct mgcp_response *r, const char *line)
{
struct in_addr ip_test;
if (strlen(line) < 16)
goto response_parse_failure;
/* The current implementation strictly supports IPV4 only ! */
if (memcmp("c=IN IP4 ", line, 9) != 0)
goto response_parse_failure;
/* Extract IP-Address */
osmo_strlcpy(r->audio_ip, line + 9, sizeof(r->audio_ip));
/* Check IP-Address */
if (inet_aton(r->audio_ip, &ip_test) == 0)
goto response_parse_failure;
return 0;
response_parse_failure:
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse MGCP response header (audio ip)\n");
"Failed to parse MGCP response header\n");
return -EINVAL;
}
@@ -235,18 +208,13 @@ int mgcp_response_parse_params(struct mgcp_response *r)
*data = '\0';
data ++;
for_each_non_empty_line(line, data) {
for_each_line(line, data) {
if (!mgcp_line_is_valid(line))
return -EINVAL;
switch (line[0]) {
case 'm':
rc = mgcp_parse_audio_port(r, line);
if (rc)
return rc;
break;
case 'c':
rc = mgcp_parse_audio_ip(r, line);
rc = mgcp_parse_audio(r, line);
if (rc)
return rc;
break;
@@ -258,65 +226,15 @@ int mgcp_response_parse_params(struct mgcp_response *r)
return 0;
}
/* Parse a line like "I: 0cedfd5a19542d197af9afe5231f1d61" */
static int mgcp_parse_conn_id(struct mgcp_response *r, const char *line)
{
if (strlen(line) < 4)
goto response_parse_failure;
if (memcmp("I: ", line, 3) != 0)
goto response_parse_failure;
osmo_strlcpy(r->head.conn_id, line + 3, sizeof(r->head.conn_id));
return 0;
response_parse_failure:
LOGP(DLMGCP, LOGL_ERROR,
"Failed to parse MGCP response (connectionIdentifier)\n");
return -EINVAL;
}
/* Parse MGCP parameters of the response */
static int parse_head_params(struct mgcp_response *r)
{
char *line;
int rc = 0;
OSMO_ASSERT(r->body);
char *data = r->body;
char *data_end = strstr(r->body, "\n\n");
/* Protect SDP body, for_each_non_empty_line() will
* only parse until it hits \0 mark. */
if (data_end)
*data_end = '\0';
for_each_non_empty_line(line, data) {
switch (line[0]) {
case 'I':
rc = mgcp_parse_conn_id(r, line);
if (rc)
goto exit;
break;
default:
/* skip unhandled parameters */
break;
}
}
exit:
/* Restore original state */
if (data_end)
*data_end = '\n';
return rc;
}
static struct mgcp_response_pending *mgcp_client_response_pending_get(
struct mgcp_client *mgcp,
mgcp_trans_id_t trans_id)
static struct mgcp_response_pending *mgcpgw_client_response_pending_get(
struct mgcpgw_client *mgcp,
struct mgcp_response *r)
{
struct mgcp_response_pending *pending;
if (!r)
return NULL;
llist_for_each_entry(pending, &mgcp->responses_pending, entry) {
if (pending->trans_id == trans_id) {
if (pending->trans_id == r->head.trans_id) {
llist_del(&pending->entry);
return pending;
}
@@ -330,7 +248,7 @@ static struct mgcp_response_pending *mgcp_client_response_pending_get(
* mgcp_do_read that reads from the socket connected to the MGCP gateway. This
* function is published mainly to be able to feed data from the test suite.
*/
int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg)
{
struct mgcp_response r = { 0 };
struct mgcp_response_pending *pending;
@@ -338,31 +256,25 @@ int mgcp_client_rx(struct mgcp_client *mgcp, struct msgb *msg)
rc = mgcp_response_parse_head(&r, msg);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head)\n");
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response\n");
return -1;
}
rc = parse_head_params(&r);
if (rc) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot parse MGCP response (head parameters)\n");
return -1;
}
pending = mgcp_client_response_pending_get(mgcp, r.head.trans_id);
pending = mgcpgw_client_response_pending_get(mgcp, &r);
if (!pending) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find matching MGCP transaction for trans_id %d\n",
r.head.trans_id);
return -ENOENT;
return -1;
}
mgcp_client_handle_response(mgcp, pending, &r);
mgcpgw_client_handle_response(mgcp, pending, &r);
return 0;
}
static int mgcp_do_read(struct osmo_fd *fd)
{
struct mgcp_client *mgcp = fd->data;
struct mgcpgw_client *mgcp = fd->data;
struct msgb *msg;
int ret;
@@ -381,10 +293,10 @@ static int mgcp_do_read(struct osmo_fd *fd)
LOGP(DLMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
msgb_free(msg);
return -1;
}
}
msg->l2h = msgb_put(msg, ret);
ret = mgcp_client_rx(mgcp, msg);
ret = mgcpgw_client_rx(mgcp, msg);
talloc_free(msg);
return ret;
}
@@ -396,7 +308,7 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
unsigned int l = msg->len < sizeof(strbuf) ? msg->len : sizeof(strbuf);
unsigned int i;
osmo_strlcpy(strbuf, (const char*)msg->data, l);
strncpy(strbuf, (const char*)msg->data, l);
for (i = 0; i < sizeof(strbuf); i++) {
if (strbuf[i] == '\n' || strbuf[i] == '\r') {
strbuf[i] = '\0';
@@ -415,12 +327,12 @@ static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg)
return ret;
}
struct mgcp_client *mgcp_client_init(void *ctx,
struct mgcp_client_conf *conf)
struct mgcpgw_client *mgcpgw_client_init(void *ctx,
struct mgcpgw_client_conf *conf)
{
struct mgcp_client *mgcp;
struct mgcpgw_client *mgcp;
mgcp = talloc_zero(ctx, struct mgcp_client);
mgcp = talloc_zero(ctx, struct mgcpgw_client);
INIT_LLIST_HEAD(&mgcp->responses_pending);
INIT_LLIST_HEAD(&mgcp->inuse_endpoints);
@@ -428,14 +340,14 @@ struct mgcp_client *mgcp_client_init(void *ctx,
mgcp->next_trans_id = 1;
mgcp->actual.local_addr = conf->local_addr ? conf->local_addr :
MGCP_CLIENT_LOCAL_ADDR_DEFAULT;
MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT;
mgcp->actual.local_port = conf->local_port >= 0 ? (uint16_t)conf->local_port :
MGCP_CLIENT_LOCAL_PORT_DEFAULT;
MGCPGW_CLIENT_LOCAL_PORT_DEFAULT;
mgcp->actual.remote_addr = conf->remote_addr ? conf->remote_addr :
MGCP_CLIENT_REMOTE_ADDR_DEFAULT;
MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT;
mgcp->actual.remote_port = conf->remote_port >= 0 ? (uint16_t)conf->remote_port :
MGCP_CLIENT_REMOTE_PORT_DEFAULT;
MGCPGW_CLIENT_REMOTE_PORT_DEFAULT;
mgcp->actual.first_endpoint = conf->first_endpoint > 0 ? (uint16_t)conf->first_endpoint : 0;
mgcp->actual.last_endpoint = conf->last_endpoint > 0 ? (uint16_t)conf->last_endpoint : 0;
@@ -444,8 +356,9 @@ struct mgcp_client *mgcp_client_init(void *ctx,
return mgcp;
}
int mgcp_client_connect(struct mgcp_client *mgcp)
int mgcpgw_client_connect(struct mgcpgw_client *mgcp)
{
int on;
struct sockaddr_in addr;
struct osmo_wqueue *wq;
int rc;
@@ -457,19 +370,46 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
wq = &mgcp->wq;
rc = osmo_sock_init2_ofd(&wq->bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
if (rc < 0) {
wq->bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (wq->bfd.fd < 0) {
LOGP(DLMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
return -errno;
}
on = 1;
if (setsockopt(wq->bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
LOGP(DLMGCP, LOGL_FATAL,
"Failed to initialize socket %s:%u -> %s:%u for MGCP GW: %s\n",
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port, strerror(errno));
"Failed to initialize socket for MGCP GW: %s\n",
strerror(errno));
rc = -errno;
goto error_close_fd;
}
/* bind socket */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(mgcp->actual.local_addr, &addr.sin_addr);
addr.sin_port = htons(mgcp->actual.local_port);
if (bind(wq->bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
LOGP(DLMGCP, LOGL_FATAL,
"Failed to bind for MGCP GW to %s %u\n",
mgcp->actual.local_addr, mgcp->actual.local_port);
rc = -errno;
goto error_close_fd;
}
/* connect to the remote */
inet_aton(mgcp->actual.remote_addr, &addr.sin_addr);
addr.sin_port = htons(mgcp->actual.remote_port);
if (connect(wq->bfd.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
LOGP(DLMGCP, LOGL_FATAL,
"Failed to connect to MGCP GW at %s %u: %s\n",
mgcp->actual.remote_addr, mgcp->actual.remote_port,
strerror(errno));
rc = -errno;
goto error_close_fd;
}
mgcp->remote_addr = htonl(addr.sin_addr.s_addr);
osmo_wqueue_init(wq, 10);
@@ -478,6 +418,11 @@ int mgcp_client_connect(struct mgcp_client *mgcp)
wq->read_cb = mgcp_do_read;
wq->write_cb = mgcp_do_write;
if (osmo_fd_register(&wq->bfd) != 0) {
LOGP(DLMGCP, LOGL_FATAL, "Failed to register BFD\n");
rc = -EIO;
goto error_close_fd;
}
LOGP(DLMGCP, LOGL_INFO, "MGCP GW connection: %s:%u -> %s:%u\n",
mgcp->actual.local_addr, mgcp->actual.local_port,
mgcp->actual.remote_addr, mgcp->actual.remote_port);
@@ -489,24 +434,24 @@ error_close_fd:
return rc;
}
const char *mgcp_client_remote_addr_str(struct mgcp_client *mgcp)
const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp)
{
return mgcp->actual.remote_addr;
}
uint16_t mgcp_client_remote_port(struct mgcp_client *mgcp)
uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp)
{
return mgcp->actual.remote_port;
}
/* Return the MGCP GW binary IPv4 address in network byte order. */
uint32_t mgcp_client_remote_addr_n(struct mgcp_client *mgcp)
uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp)
{
return mgcp->remote_addr;
}
struct mgcp_response_pending * mgcp_client_pending_add(
struct mgcp_client *mgcp,
struct mgcp_response_pending * mgcpgw_client_pending_add(
struct mgcpgw_client *mgcp,
mgcp_trans_id_t trans_id,
mgcp_response_cb_t response_cb,
void *priv)
@@ -526,12 +471,9 @@ struct mgcp_response_pending * mgcp_client_pending_add(
* response_cb. NOTE: the response_cb still needs to call
* mgcp_response_parse_params(response) to get the parsed parameters -- to
* potentially save some CPU cycles, only the head line has been parsed when
* the response_cb is invoked.
* Before the priv pointer becomes invalid, e.g. due to transaction timeout,
* mgcp_client_cancel() needs to be called for this transaction.
*/
int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv)
* the response_cb is invoked. */
int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
mgcp_response_cb_t response_cb, void *priv)
{
struct mgcp_response_pending *pending;
mgcp_trans_id_t trans_id;
@@ -545,7 +487,7 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
return -EINVAL;
}
pending = mgcp_client_pending_add(mgcp, trans_id, response_cb, priv);
pending = mgcpgw_client_pending_add(mgcp, trans_id, response_cb, priv);
if (msgb_l2len(msg) > 4096) {
LOGP(DLMGCP, LOGL_ERROR,
@@ -568,36 +510,10 @@ int mgcp_client_tx(struct mgcp_client *mgcp, struct msgb *msg,
mgcp_tx_error:
/* Pass NULL to response cb to indicate an error */
mgcp_client_handle_response(mgcp, pending, NULL);
mgcpgw_client_handle_response(mgcp, pending, NULL);
return -1;
}
/* Cancel a pending transaction.
* Should a priv pointer passed to mgcp_client_tx() become invalid, this function must be called. In
* practical terms, if the caller of mgcp_client_tx() wishes to tear down a transaction without having
* received a response this function must be called. The trans_id can be obtained by calling
* mgcp_msg_trans_id() on the msgb produced by mgcp_msg_gen().
*/
int mgcp_client_cancel(struct mgcp_client *mgcp, mgcp_trans_id_t trans_id)
{
struct mgcp_response_pending *pending = mgcp_client_response_pending_get(mgcp, trans_id);
if (!pending) {
/* INFO is sufficient, it is not harmful to cancel a transaction twice. */
LOGP(DLMGCP, LOGL_INFO, "Cannot cancel, no such transaction: %u\n", trans_id);
return -ENOENT;
}
LOGP(DLMGCP, LOGL_INFO, "Canceled transaction %u\n", trans_id);
talloc_free(pending);
return 0;
/* We don't really need to clean up the wqueue: In all sane cases, the msgb has already been sent
* out and is no longer in the wqueue. If it still is in the wqueue, then sending MGCP messages
* per se is broken and the program should notice so by a full wqueue. Even if this was called
* before we had a chance to send out the message and it is still going to be sent, we will just
* ignore the reply to it later. Removing a msgb from the wqueue here would just introduce more
* bug surface in terms of failing to update wqueue API's counters or some such.
*/
}
static struct msgb *mgcp_msg_from_buf(mgcp_trans_id_t trans_id,
const char *buf, int len)
{
@@ -646,7 +562,7 @@ static struct msgb *mgcp_msg_from_str(mgcp_trans_id_t trans_id,
return mgcp_msg_from_buf(trans_id, compose, len);
}
static mgcp_trans_id_t mgcp_client_next_trans_id(struct mgcp_client *mgcp)
static mgcp_trans_id_t mgcpgw_client_next_trans_id(struct mgcpgw_client *mgcp)
{
/* avoid zero trans_id to distinguish from unset trans_id */
if (!mgcp->next_trans_id)
@@ -654,11 +570,11 @@ static mgcp_trans_id_t mgcp_client_next_trans_id(struct mgcp_client *mgcp)
return mgcp->next_trans_id ++;
}
struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, unsigned int call_id,
enum mgcp_connection_mode mode)
{
mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
return mgcp_msg_from_str(trans_id,
"CRCX %u %x@mgw MGCP 1.0\r\n"
"C: %x\r\n"
@@ -668,15 +584,15 @@ struct msgb *mgcp_msg_crcx(struct mgcp_client *mgcp,
trans_id,
rtp_endpoint,
call_id,
mgcp_client_cmode_name(mode));
mgcp_cmode_name(mode));
}
struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode)
{
mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
return mgcp_msg_from_str(trans_id,
"MDCX %u %x@mgw MGCP 1.0\r\n"
"M: %s\r\n"
@@ -686,163 +602,21 @@ struct msgb *mgcp_msg_mdcx(struct mgcp_client *mgcp,
,
trans_id,
rtp_endpoint,
mgcp_client_cmode_name(mode),
mgcp_cmode_name(mode),
rtp_conn_addr,
rtp_port);
}
struct msgb *mgcp_msg_dlcx(struct mgcp_client *mgcp, uint16_t rtp_endpoint,
struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
unsigned int call_id)
{
mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
mgcp_trans_id_t trans_id = mgcpgw_client_next_trans_id(mgcp);
return mgcp_msg_from_str(trans_id,
"DLCX %u %x@mgw MGCP 1.0\r\n"
"C: %x\r\n", trans_id, rtp_endpoint, call_id);
}
#define MGCP_CRCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
MGCP_MSG_PRESENCE_CALL_ID | \
MGCP_MSG_PRESENCE_CONN_MODE)
#define MGCP_MDCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT | \
MGCP_MSG_PRESENCE_CONN_ID)
#define MGCP_DLCX_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT)
#define MGCP_AUEP_MANDATORY (MGCP_MSG_PRESENCE_ENDPOINT)
#define MGCP_RSIP_MANDATORY 0 /* none */
struct msgb *mgcp_msg_gen(struct mgcp_client *mgcp, struct mgcp_msg *mgcp_msg)
{
mgcp_trans_id_t trans_id = mgcp_client_next_trans_id(mgcp);
uint32_t mandatory_mask;
struct msgb *msg = msgb_alloc_headroom(4096, 128, "MGCP tx");
int rc = 0;
msg->l2h = msg->data;
msg->cb[MSGB_CB_MGCP_TRANS_ID] = trans_id;
/* Add command verb */
switch (mgcp_msg->verb) {
case MGCP_VERB_CRCX:
mandatory_mask = MGCP_CRCX_MANDATORY;
rc += msgb_printf(msg, "CRCX %u", trans_id);
break;
case MGCP_VERB_MDCX:
mandatory_mask = MGCP_MDCX_MANDATORY;
rc += msgb_printf(msg, "MDCX %u", trans_id);
break;
case MGCP_VERB_DLCX:
mandatory_mask = MGCP_DLCX_MANDATORY;
rc += msgb_printf(msg, "DLCX %u", trans_id);
break;
case MGCP_VERB_AUEP:
mandatory_mask = MGCP_AUEP_MANDATORY;
rc += msgb_printf(msg, "AUEP %u", trans_id);
break;
case MGCP_VERB_RSIP:
mandatory_mask = MGCP_RSIP_MANDATORY;
rc += msgb_printf(msg, "RSIP %u", trans_id);
break;
default:
LOGP(DLMGCP, LOGL_ERROR,
"Invalid command verb, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
/* Check if mandatory fields are missing */
if (!((mgcp_msg->presence & mandatory_mask) == mandatory_mask)) {
LOGP(DLMGCP, LOGL_ERROR,
"One or more missing mandatory fields, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
/* Add endpoint name */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_ENDPOINT) {
if (strlen(mgcp_msg->endpoint) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty endpoint name, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, " %s", mgcp_msg->endpoint);
}
/* Add protocol version */
rc += msgb_printf(msg, " MGCP 1.0\r\n");
/* Add call id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CALL_ID)
rc += msgb_printf(msg, "C: %x\r\n", mgcp_msg->call_id);
/* Add connection id */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_ID) {
if (strlen(mgcp_msg->conn_id) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty connection id, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, "I: %s\r\n", mgcp_msg->conn_id);
}
/* Add local connection options */
if (mgcp_msg->verb == MGCP_VERB_CRCX)
rc += msgb_printf(msg, "L: p:20, a:AMR, nt:IN\r\n");
/* Add mode */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_CONN_MODE)
rc +=
msgb_printf(msg, "M: %s\r\n",
mgcp_client_cmode_name(mgcp_msg->conn_mode));
/* Add RTP address and port (SDP) */
if (mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_IP
&& mgcp_msg->presence & MGCP_MSG_PRESENCE_AUDIO_PORT) {
if (mgcp_msg->audio_port == 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Invalid port number, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
if (strlen(mgcp_msg->audio_ip) <= 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Empty ip address, can not generate MGCP message\n");
msgb_free(msg);
return NULL;
}
rc += msgb_printf(msg, "\r\n");
rc += msgb_printf(msg, "c=IN IP4 %s\r\n", mgcp_msg->audio_ip);
rc +=
msgb_printf(msg, "m=audio %u RTP/AVP 255\r\n",
mgcp_msg->audio_port);
}
if (rc != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"message buffer to small, can not generate MGCP message\n");
msgb_free(msg);
msg = NULL;
}
return msg;
}
/* Retrieve the MGCP transaction ID from a msgb generated by mgcp_msg_gen() */
mgcp_trans_id_t mgcp_msg_trans_id(struct msgb *msg)
{
return (mgcp_trans_id_t)msg->cb[MSGB_CB_MGCP_TRANS_ID];
}
struct mgcp_client_conf *mgcp_client_conf_actual(struct mgcp_client *mgcp)
struct mgcpgw_client_conf *mgcpgw_client_conf_actual(struct mgcpgw_client *mgcp)
{
return &mgcp->actual;
}
const struct value_string mgcp_client_connection_mode_strs[] = {
{ MGCP_CONN_NONE, "none" },
{ MGCP_CONN_RECV_SEND, "sendrecv" },
{ MGCP_CONN_SEND_ONLY, "sendonly" },
{ MGCP_CONN_RECV_ONLY, "recvonly" },
{ MGCP_CONN_LOOPBACK, "loopback" },
{ 0, NULL }
};

View File

@@ -0,0 +1,172 @@
/* MGCPGW client interface to quagga VTY */
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2011 by Holger Hans Peter Freyther
* 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 <inttypes.h>
#include <stdlib.h>
#include <talloc.h>
#include <osmocom/vty/command.h>
#include <osmocom/core/utils.h>
#include <osmocom/legacy_mgcp/vty.h>
#include <osmocom/legacy_mgcp/mgcpgw_client.h>
#define MGCPGW_STR "MGCP gateway configuration for RTP streams\n"
void *global_mgcpgw_client_ctx = NULL;
struct mgcpgw_client_conf *global_mgcpgw_client_conf = NULL;
DEFUN(cfg_mgcpgw_local_ip, cfg_mgcpgw_local_ip_cmd,
"mgcpgw local-ip A.B.C.D",
MGCPGW_STR "local bind to connect to MGCP gateway with\n"
"local bind IP address\n")
{
if (!global_mgcpgw_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcpgw_client_ctx);
global_mgcpgw_client_conf->local_addr =
talloc_strdup(global_mgcpgw_client_ctx, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcpgw_local_port, cfg_mgcpgw_local_port_cmd,
"mgcpgw local-port <0-65535>",
MGCPGW_STR "local bind to connect to MGCP gateway with\n"
"local bind port\n")
{
if (!global_mgcpgw_client_conf)
return CMD_ERR_NOTHING_TODO;
global_mgcpgw_client_conf->local_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcpgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
"mgcpgw remote-ip A.B.C.D",
MGCPGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind IP address\n")
{
if (!global_mgcpgw_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcpgw_client_ctx);
global_mgcpgw_client_conf->remote_addr =
talloc_strdup(global_mgcpgw_client_ctx, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcpgw_remote_port, cfg_mgcpgw_remote_port_cmd,
"mgcpgw remote-port <0-65535>",
MGCPGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind port\n")
{
if (!global_mgcpgw_client_conf)
return CMD_ERR_NOTHING_TODO;
global_mgcpgw_client_conf->remote_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcpgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
"mgcpgw endpoint-range <1-65534> <1-65534>",
MGCPGW_STR "usable range of endpoint identifiers\n"
"set first useable endpoint identifier\n"
"set the last useable endpoint identifier\n")
{
uint16_t first_endpoint = atoi(argv[0]);
uint16_t last_endpoint = atoi(argv[1]);
if (last_endpoint < first_endpoint) {
vty_out(vty, "last endpoint must be greater than first endpoint!%s",
VTY_NEWLINE);
return CMD_SUCCESS;
}
global_mgcpgw_client_conf->first_endpoint = first_endpoint;
global_mgcpgw_client_conf->last_endpoint = last_endpoint;
return CMD_SUCCESS;
}
#define BTS_START_STR "First UDP port allocated for the BTS side\n"
#define UDP_PORT_STR "UDP Port number\n"
DEFUN(cfg_mgcp_rtp_bts_base_port,
cfg_mgcp_rtp_bts_base_port_cmd,
"mgcpgw bts-base <0-65534>",
MGCPGW_STR
BTS_START_STR
UDP_PORT_STR)
{
global_mgcpgw_client_conf->bts_base = atoi(argv[0]);
return CMD_SUCCESS;
}
int mgcpgw_client_config_write(struct vty *vty, const char *indent)
{
const char *addr;
int port;
uint16_t first_endpoint;
uint16_t last_endpoint;
uint16_t bts_base;
addr = global_mgcpgw_client_conf->local_addr;
if (addr)
vty_out(vty, "%smgcpgw local-ip %s%s", indent, addr,
VTY_NEWLINE);
port = global_mgcpgw_client_conf->local_port;
if (port >= 0)
vty_out(vty, "%smgcpgw local-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
addr = global_mgcpgw_client_conf->remote_addr;
if (addr)
vty_out(vty, "%smgcpgw remote-ip %s%s", indent, addr,
VTY_NEWLINE);
port = global_mgcpgw_client_conf->remote_port;
if (port >= 0)
vty_out(vty, "%smgcpgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
first_endpoint = global_mgcpgw_client_conf->first_endpoint;
last_endpoint = global_mgcpgw_client_conf->last_endpoint;
if (last_endpoint != 0) {
vty_out(vty, "%smgcpgw endpoint-range %u %u%s", indent,
first_endpoint, last_endpoint, VTY_NEWLINE);
}
bts_base = global_mgcpgw_client_conf->bts_base;
if (bts_base) {
vty_out(vty, "%smgcpgw bts-base %u%s", indent,
bts_base, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
void mgcpgw_client_vty_init(void *talloc_ctx, int node, struct mgcpgw_client_conf *conf)
{
global_mgcpgw_client_ctx = talloc_ctx;
global_mgcpgw_client_conf = conf;
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_mgcp_rtp_bts_base_port_cmd);
}

View File

@@ -1,34 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)
# 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=2:0:0
lib_LTLIBRARIES = \
libosmo-mgcp-client.la \
$(NULL)
libosmo_mgcp_client_la_SOURCES = \
mgcp_client.c \
mgcp_client_vty.c \
$(NULL)
libosmo_mgcp_client_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_CLIENT_LIBVERSION)

View File

@@ -1,206 +0,0 @@
/* MGCP client interface to quagga VTY */
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2011 by Holger Hans Peter Freyther
* 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 <inttypes.h>
#include <stdlib.h>
#include <talloc.h>
#include <osmocom/vty/command.h>
#include <osmocom/core/utils.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#define MGW_STR "Configure MGCP connection to Media Gateway\n"
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 A.B.C.D",
MGW_STR "local bind to connect to MGW from\n"
"local bind IP address\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcp_client_ctx);
global_mgcp_client_conf->local_addr =
talloc_strdup(global_mgcp_client_ctx, argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_local_ip, cfg_mgcpgw_local_ip_cmd,
"mgcpgw local-ip A.B.C.D",
MGW_STR "local bind to connect to MGCP gateway with\n"
"local bind IP address\n")
DEFUN(cfg_mgw_local_port, cfg_mgw_local_port_cmd,
"mgw local-port <0-65535>",
MGW_STR "local port to connect to MGW from\n"
"local bind port\n")
{
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,
"mgcpgw local-port <0-65535>",
MGW_STR "local bind to connect to MGCP gateway with\n"
"local bind port\n")
DEFUN(cfg_mgw_remote_ip, cfg_mgw_remote_ip_cmd,
"mgw remote-ip A.B.C.D",
MGW_STR "remote IP address to reach the MGW at\n"
"remote IP address\n")
{
if (!global_mgcp_client_conf)
return CMD_ERR_NOTHING_TODO;
OSMO_ASSERT(global_mgcp_client_ctx);
global_mgcp_client_conf->remote_addr =
talloc_strdup(global_mgcp_client_ctx, argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_remote_ip, cfg_mgcpgw_remote_ip_cmd,
"mgcpgw remote-ip A.B.C.D",
MGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind IP address\n")
DEFUN(cfg_mgw_remote_port, cfg_mgw_remote_port_cmd,
"mgw remote-port <0-65535>",
MGW_STR "remote port to reach the MGW at\n"
"remote port\n")
{
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,
"mgcpgw remote-port <0-65535>",
MGW_STR "remote bind to connect to MGCP gateway with\n"
"remote bind port\n")
DEFUN(cfg_mgw_endpoint_range, cfg_mgw_endpoint_range_cmd,
"mgw endpoint-range <1-65534> <1-65534>",
MGW_STR "usable range of endpoint identifiers\n"
"set first usable endpoint identifier\n"
"set last usable endpoint identifier\n")
{
uint16_t first_endpoint = atoi(argv[0]);
uint16_t last_endpoint = atoi(argv[1]);
if (last_endpoint < first_endpoint) {
vty_out(vty, "last endpoint must be greater than first endpoint!%s",
VTY_NEWLINE);
return CMD_SUCCESS;
}
global_mgcp_client_conf->first_endpoint = first_endpoint;
global_mgcp_client_conf->last_endpoint = last_endpoint;
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_endpoint_range, cfg_mgcpgw_endpoint_range_cmd,
"mgcpgw endpoint-range <1-65534> <1-65534>",
MGW_STR "usable range of endpoint identifiers\n"
"set first useable endpoint identifier\n"
"set the last useable endpoint identifier\n")
#define BTS_START_STR "First UDP port allocated for the BTS side\n"
#define UDP_PORT_STR "UDP Port number\n"
DEFUN(cfg_mgw_rtp_bts_base_port,
cfg_mgw_rtp_bts_base_port_cmd,
"mgw bts-base <0-65534>",
MGW_STR
BTS_START_STR
UDP_PORT_STR)
{
global_mgcp_client_conf->bts_base = atoi(argv[0]);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgw_rtp_bts_base_port,
cfg_mgcpgw_rtp_bts_base_port_cmd,
"mgcpgw bts-base <0-65534>",
MGW_STR
BTS_START_STR
UDP_PORT_STR)
int mgcp_client_config_write(struct vty *vty, const char *indent)
{
const char *addr;
int port;
uint16_t first_endpoint;
uint16_t last_endpoint;
uint16_t bts_base;
addr = global_mgcp_client_conf->local_addr;
if (addr)
vty_out(vty, "%smgw local-ip %s%s", indent, addr,
VTY_NEWLINE);
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 = global_mgcp_client_conf->remote_addr;
if (addr)
vty_out(vty, "%smgw remote-ip %s%s", indent, addr,
VTY_NEWLINE);
port = global_mgcp_client_conf->remote_port;
if (port >= 0)
vty_out(vty, "%smgw remote-port %u%s", indent,
(uint16_t)port, VTY_NEWLINE);
first_endpoint = global_mgcp_client_conf->first_endpoint;
last_endpoint = global_mgcp_client_conf->last_endpoint;
if (last_endpoint != 0) {
vty_out(vty, "%smgw endpoint-range %u %u%s", indent,
first_endpoint, last_endpoint, VTY_NEWLINE);
}
bts_base = global_mgcp_client_conf->bts_base;
if (bts_base) {
vty_out(vty, "%smgw bts-base %u%s", indent,
bts_base, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
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_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);
/* 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);
}

View File

@@ -1,48 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(COVERAGE_LDFLAGS) \
$(NULL)
# 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_LIBVERSION=1:0:0
lib_LTLIBRARIES = \
libosmo-mgcp.la \
$(NULL)
noinst_HEADERS = \
g711common.h \
$(NULL)
libosmo_mgcp_la_SOURCES = \
mgcp_protocol.c \
mgcp_network.c \
mgcp_vty.c \
mgcp_osmux.c \
mgcp_sdp.c \
mgcp_msg.c \
mgcp_conn.c \
mgcp_stat.c \
mgcp_ep.c \
$(NULL)
libosmo_mgcp_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(MGCP_LIBVERSION)

View File

@@ -1,187 +0,0 @@
/*
* PCM - A-Law conversion
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
* Wrapper for linphone Codec class by Simon Morlat <simon.morlat@linphone.org>
*
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
static inline int val_seg(int val)
{
int r = 0;
val >>= 7; /*7 = 4 + 3*/
if (val & 0xf0) {
val >>= 4;
r += 4;
}
if (val & 0x0c) {
val >>= 2;
r += 2;
}
if (val & 0x02)
r += 1;
return r;
}
/*
* s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
*
* s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
*
* Linear Input Code Compressed Code
* ------------------------ ---------------
* 0000000wxyza 000wxyz
* 0000001wxyza 001wxyz
* 000001wxyzab 010wxyz
* 00001wxyzabc 011wxyz
* 0001wxyzabcd 100wxyz
* 001wxyzabcde 101wxyz
* 01wxyzabcdef 110wxyz
* 1wxyzabcdefg 111wxyz
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
* G711 is designed for 13 bits input signal, this function add extra shifting to take this into account.
*/
static inline unsigned char s16_to_alaw(int pcm_val)
{
int mask;
int seg;
unsigned char aval;
if (pcm_val >= 0) {
mask = 0xD5;
} else {
mask = 0x55;
pcm_val = -pcm_val;
if (pcm_val > 0x7fff)
pcm_val = 0x7fff;
}
if (pcm_val < 256) /*256 = 32 << 3*/
aval = pcm_val >> 4; /*4 = 1 + 3*/
else {
/* Convert the scaled magnitude to segment number. */
seg = val_seg(pcm_val);
aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
}
return aval ^ mask;
}
/*
* alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
*
*/
static inline int alaw_to_s16(unsigned char a_val)
{
int t;
int seg;
a_val ^= 0x55;
t = a_val & 0x7f;
if (t < 16)
t = (t << 4) + 8;
else {
seg = (t >> 4) & 0x07;
t = ((t & 0x0f) << 4) + 0x108;
t <<= seg -1;
}
return ((a_val & 0x80) ? t : -t);
}
/*
* s16_to_ulaw() - Convert a linear PCM value to u-law
*
* In order to simplify the encoding process, the original linear magnitude
* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
* (33 - 8191). The result can be seen in the following encoding table:
*
* Biased Linear Input Code Compressed Code
* ------------------------ ---------------
* 00000001wxyza 000wxyz
* 0000001wxyzab 001wxyz
* 000001wxyzabc 010wxyz
* 00001wxyzabcd 011wxyz
* 0001wxyzabcde 100wxyz
* 001wxyzabcdef 101wxyz
* 01wxyzabcdefg 110wxyz
* 1wxyzabcdefgh 111wxyz
*
* Each biased linear code has a leading 1 which identifies the segment
* number. The value of the segment number is equal to 7 minus the number
* of leading 0's. The quantization interval is directly available as the
* four bits wxyz. * The trailing bits (a - h) are ignored.
*
* Ordinarily the complement of the resulting code word is used for
* transmission, and so the code word is complemented before it is returned.
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
{
int mask;
int seg;
unsigned char uval;
if (pcm_val < 0) {
pcm_val = 0x84 - pcm_val;
mask = 0x7f;
} else {
pcm_val += 0x84;
mask = 0xff;
}
if (pcm_val > 0x7fff)
pcm_val = 0x7fff;
/* Convert the scaled magnitude to segment number. */
seg = val_seg(pcm_val);
/*
* Combine the sign, segment, quantization bits;
* and complement the code word.
*/
uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
return uval ^ mask;
}
/*
* ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
*
* First, a biased linear code is derived from the code word. An unbiased
* output can then be obtained by subtracting 33 from the biased code.
*
* Note that this function expects to be passed the complement of the
* original code word. This is in keeping with ISDN conventions.
*/
static inline int ulaw_to_s16(unsigned char u_val)
{
int t;
/* Complement to obtain normal u-law value. */
u_val = ~u_val;
/*
* Extract and bias the quantization bits. Then
* shift up by the segment number and subtract out the bias.
*/
t = ((u_val & 0x0f) << 3) + 0x84;
t <<= (u_val & 0x70) >> 4;
return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
}

View File

@@ -1,311 +0,0 @@
/* Message connection list handling */
/*
* (C) 2017 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 <osmocom/mgcp/mgcp_conn.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_common.h>
#include <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/gsm/gsm_utils.h>
#include <ctype.h>
/* Allocate a new connection identifier. According to RFC3435, they must
* be unique only within the scope of the endpoint. (Caller must provide
* memory for id) */
static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id)
{
int i;
int k;
int rc;
uint8_t id_bin[16];
char *id_hex;
/* Generate a connection id that is unique for the current endpoint.
* Technically a counter would be sufficient, but in order to
* be able to find a specific connection in large logfiles and to
* prevent unintentional connections we assign the connection
* identifiers randomly from a reasonable large number space */
for (i = 0; i < 32; i++) {
rc = osmo_get_rand_id(id_bin, sizeof(id_bin));
if (rc < 0)
return rc;
id_hex = osmo_hexdump_nospc(id_bin, sizeof(id_bin));
for (k = 0; k < strlen(id_hex); k++)
id_hex[k] = toupper(id_hex[k]);
/* ensure that the generated conn_id is unique
* for this endpoint */
if (!mgcp_conn_get_rtp(endp, id_hex)) {
osmo_strlcpy(id, id_hex, MGCP_CONN_ID_LENGTH);
return 0;
}
}
LOGP(DLMGCP, LOGL_ERROR, "endpoint:0x%x, unable to generate a unique connectionIdentifier\n",
ENDPOINT_NUMBER(endp));
return -1;
}
/* Reset codec state and free memory */
static void mgcp_rtp_codec_reset(struct mgcp_rtp_codec *codec)
{
codec->payload_type = -1;
codec->subtype_name = NULL;
codec->audio_name = NULL;
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;
/* see also mgcp_sdp.c, mgcp_set_audio_info() */
talloc_free(codec->subtype_name);
talloc_free(codec->audio_name);
}
/* Reset states, free memory, set defaults and reset codec state */
static void mgcp_rtp_conn_reset(struct mgcp_conn_rtp *conn)
{
struct mgcp_rtp_end *end = &conn->end;
conn->type = MGCP_RTP_DEFAULT;
conn->osmux.allocated_cid = -1;
end->rtp.fd = -1;
end->rtcp.fd = -1;
end->local_port = 0;
end->packets_rx = 0;
end->octets_rx = 0;
end->packets_tx = 0;
end->octets_tx = 0;
end->dropped_packets = 0;
end->rtp_port = end->rtcp_port = 0;
talloc_free(end->fmtp_extra);
end->fmtp_extra = NULL;
/* Set default values */
end->frames_per_packet = 0; /* unknown */
end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS;
end->output_enabled = 0;
mgcp_rtp_codec_reset(&end->codec);
mgcp_rtp_codec_reset(&end->alt_codec);
}
/*! allocate a new connection list entry.
* \param[in] ctx talloc context
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \param[in] type connection type (e.g. MGCP_CONN_TYPE_RTP)
* \returns pointer to allocated connection, NULL on error */
struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp,
enum mgcp_conn_type type, char *name)
{
struct mgcp_conn *conn;
int rc;
/* Do not allow more then two connections */
if (llist_count(&endp->conns) >= endp->type->max_conns)
return NULL;
/* Create new connection and add it to the list */
conn = talloc_zero(ctx, struct mgcp_conn);
if (!conn)
return NULL;
conn->endp = endp;
conn->type = type;
conn->mode = MGCP_CONN_NONE;
conn->mode_orig = MGCP_CONN_NONE;
conn->u.rtp.conn = conn;
osmo_strlcpy(conn->name, name, sizeof(conn->name));
rc = mgcp_alloc_id(endp, conn->id);
if (rc < 0) {
talloc_free(conn);
return NULL;
}
switch (type) {
case MGCP_CONN_TYPE_RTP:
mgcp_rtp_conn_reset(&conn->u.rtp);
break;
default:
/* NOTE: This should never be called with an
* invalid type, its up to the programmer
* to ensure propery types */
OSMO_ASSERT(false);
}
llist_add(&conn->entry, &endp->conns);
return conn;
}
/*! find a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id)
{
struct mgcp_conn *conn;
llist_for_each_entry(conn, &endp->conns, entry) {
if (strncmp(conn->id, id, sizeof(conn->id)) == 0)
return conn;
}
return NULL;
}
/*! find an RTP connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection
* \returns pointer to allocated connection, NULL if not found */
struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp,
const char *id)
{
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
if (!conn)
return NULL;
if (conn->type == MGCP_CONN_TYPE_RTP)
return &conn->u.rtp;
return NULL;
}
/*! free a connection by its ID.
* \param[in] endp associated endpoint
* \param[in] id identification number of the connection */
void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id)
{
struct mgcp_conn *conn;
conn = mgcp_conn_get(endp, id);
if (!conn)
return;
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
osmux_disable_conn(&conn->u.rtp);
osmux_release_cid(&conn->u.rtp);
mgcp_free_rtp_port(&conn->u.rtp.end);
break;
default:
/* NOTE: This should never be called with an
* invalid type, its up to the programmer
* to ensure propery types */
OSMO_ASSERT(false);
}
llist_del(&conn->entry);
talloc_free(conn);
}
/*! free oldest connection in the list.
* \param[in] endp associated endpoint */
void mgcp_conn_free_oldest(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
if (llist_empty(&endp->conns))
return;
conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry);
if (!conn)
return;
mgcp_conn_free(endp, conn->id);
}
/*! free all connections at once.
* \param[in] endp associated endpoint */
void mgcp_conn_free_all(struct mgcp_endpoint *endp)
{
struct mgcp_conn *conn;
struct mgcp_conn *conn_tmp;
/* Drop all items in the list */
llist_for_each_entry_safe(conn, conn_tmp, &endp->conns, entry) {
mgcp_conn_free(endp, conn->id);
}
return;
}
/*! dump basic connection information to human readble string.
* \param[in] conn to dump
* \returns human readble string */
char *mgcp_conn_dump(struct mgcp_conn *conn)
{
static char str[sizeof(conn->name)+sizeof(conn->id)+256];
if (!conn) {
snprintf(str, sizeof(str), "(null connection)");
return str;
}
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
/* Dump RTP connection */
snprintf(str, sizeof(str), "(%s/rtp, id:0x%s, ip:%s, "
"rtp:%u rtcp:%u)",
conn->name,
conn->id,
inet_ntoa(conn->u.rtp.end.addr),
ntohs(conn->u.rtp.end.rtp_port),
ntohs(conn->u.rtp.end.rtcp_port));
break;
default:
/* Should not happen, we should be able to dump
* every possible connection type. */
snprintf(str, sizeof(str), "(unknown connection type)");
break;
}
return str;
}
/*! find destination connection on a specific endpoint.
* \param[in] conn to search a destination for
* \returns destination connection, NULL on failure */
struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn)
{
struct mgcp_endpoint *endp;
struct mgcp_conn *partner_conn;
endp = conn->endp;
/*! NOTE: This simply works by grabbing the first connection that is
* not the supplied connection, which is suitable for endpoints that
* do not serve more than two connections. */
llist_for_each_entry(partner_conn, &endp->conns, entry) {
if (conn != partner_conn) {
return partner_conn;
}
}
return NULL;
}

View File

@@ -1,32 +0,0 @@
/* Endpoint types */
/*
* (C) 2017 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 <osmocom/mgcp/mgcp_ep.h>
#include <osmocom/mgcp/mgcp_internal.h>
/* Endpoint typeset definition */
const struct mgcp_endpoint_typeset ep_typeset = {
/* Specify endpoint properties for RTP endpoint */
.rtp.max_conns = 2,
.rtp.dispatch_rtp_cb = mgcp_dispatch_rtp_bridge_cb
};

View File

@@ -1,406 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* Message parser/generator utilities */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2017 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 <limits.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>
/*! Display an mgcp message on the log output.
* \param[in] message mgcp message string
* \param[in] len message mgcp message string length
* \param[in] preamble string to display in logtext in front of each line */
void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble)
{
unsigned char line[80];
unsigned char *ptr;
unsigned int consumed = 0;
unsigned int consumed_line = 0;
unsigned int line_count = 0;
if (!log_check_level(DLMGCP, LOGL_DEBUG))
return;
while (1) {
memset(line, 0, sizeof(line));
ptr = line;
consumed_line = 0;
do {
if (*message != '\n' && *message != '\r') {
*ptr = *message;
ptr++;
}
message++;
consumed++;
consumed_line++;
} while (*message != '\n' && consumed < len
&& consumed_line < sizeof(line));
if (strlen((const char *)line)) {
LOGP(DLMGCP, LOGL_DEBUG, "%s: line #%02u: %s\n",
preamble, line_count, line);
line_count++;
}
if (consumed >= len)
return;
}
}
/*! Parse connection mode.
* \param[in] mode as string (recvonly, sendrecv, sendonly or loopback)
* \param[in] endp pointer to endpoint (only used for log output)
* \param[out] associated connection to be modified accordingly
* \returns 0 on success, -1 on error */
int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp,
struct mgcp_conn *conn)
{
int ret = 0;
if (!mode) {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x missing connection mode\n",
ENDPOINT_NUMBER(endp));
return -1;
}
if (!conn)
return -1;
if (!endp)
return -1;
if (strcmp(mode, "recvonly") == 0)
conn->mode = MGCP_CONN_RECV_ONLY;
else if (strcmp(mode, "sendrecv") == 0)
conn->mode = MGCP_CONN_RECV_SEND;
else if (strcmp(mode, "sendonly") == 0)
conn->mode = MGCP_CONN_SEND_ONLY;
else if (strcmp(mode, "loopback") == 0)
conn->mode = MGCP_CONN_LOOPBACK;
else {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x unknown connection mode: '%s'\n",
ENDPOINT_NUMBER(endp), mode);
ret = -1;
}
/* 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;
}
LOGP(DLMGCP, LOGL_DEBUG,
"endpoint:0x%x conn:%s\n",
ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn));
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) {
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
* to hold a copy of the original connection mode */
conn->mode_orig = conn->mode;
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;
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;
}
return &tcfg->endpoints[endp];
}
/* 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)
{
char *endptr = NULL;
unsigned int gw = INT_MAX;
if (strncmp(mgcp, "ds/e1", 5) == 0)
return find_e1_endpoint(cfg, mgcp);
gw = strtoul(mgcp, &endptr, 10);
if (gw > 0 && gw < cfg->trunk.number_endpoints && endptr[0] == '@')
return &cfg->trunk.endpoints[gw];
LOGP(DLMGCP, LOGL_ERROR, "Not able to find the endpoint: '%s'\n", mgcp);
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 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;
/*! This function will parse the header part of the received
* 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)) {
switch (i) {
case 0:
pdata->trans = elem;
break;
case 1:
pdata->endp = find_endpoint(pdata->cfg, elem);
if (!pdata->endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Unable to find Endpoint `%s'\n", elem);
return -1;
}
break;
case 2:
if (strcmp("MGCP", elem)) {
LOGP(DLMGCP, LOGL_ERROR,
"MGCP header parsing error\n");
return -1;
}
break;
case 3:
if (strcmp("1.0", elem)) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP version `%s' "
"not supported\n", elem);
return -1;
}
break;
}
i++;
}
if (i != 4) {
LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n");
pdata->trans = "000000";
pdata->endp = NULL;
return -1;
}
return 0;
}
/*! Extract OSMUX CID from an MGCP parameter line (string).
* \param[in] line single parameter line from the MGCP message
* \returns OSMUX CID, -1 on error */
int mgcp_parse_osmux_cid(const char *line)
{
int osmux_cid;
if (sscanf(line + 2, "Osmux: %u", &osmux_cid) != 1)
return -1;
if (osmux_cid > OSMUX_CID_MAX) {
LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n",
osmux_cid, OSMUX_CID_MAX);
return -1;
}
LOGP(DLMGCP, LOGL_DEBUG, "bsc-nat offered Osmux CID %u\n", osmux_cid);
return osmux_cid;
}
/*! Check MGCP parameter line (string) for plausibility.
* \param[in] endp pointer to endpoint (only used for log output)
* \param[in] line single parameter line from the MGCP message
* \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) {
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 1;
}
/*! Check if the specified callid seems plausible.
* \param[in] endp pointer to endpoint
* \param{in] callid to verify
* \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
* stored in the endpoint structure. */
if (!endp)
return -1;
if (!callid)
return -1;
if (!endp->callid)
return -1;
if (strcmp(endp->callid, callid) != 0) {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x CallIDs does not match '%s' != '%s'\n",
ENDPOINT_NUMBER(endp), endp->callid, callid);
return -1;
}
return 0;
}
/*! Check if the specified connection id seems plausible.
* \param[in] endp pointer to endpoint
* \param{in] connection id to verify
* \returns 1 when connection id seems plausible, 0 on error */
int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id)
{
/* Check for null identifiers */
if (!conn_id) {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x invalid ConnectionIdentifier (missing)\n",
ENDPOINT_NUMBER(endp));
return -1;
}
/* Check for empty connection identifiers */
if (strlen(conn_id) == 0) {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x invalid ConnectionIdentifier (empty)\n",
ENDPOINT_NUMBER(endp));
return -1;
}
/* Check for over long connection identifiers */
if (strlen(conn_id) > MGCP_CONN_ID_LENGTH) {
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x invalid ConnectionIdentifier (too long) 0x%s\n",
ENDPOINT_NUMBER(endp), conn_id);
return -1;
}
/* Check if connection exists */
if (mgcp_conn_get(endp, conn_id))
return 0;
LOGP(DLMGCP, LOGL_ERROR,
"endpoint:0x%x no connection found under ConnectionIdentifier 0x%s\n",
ENDPOINT_NUMBER(endp), conn_id);
return -1;
}
/*! Extract individual lines from MCGP message.
* \param[in] str MGCP message string, consisting of multiple lines
* \param{in] saveptr pointer to next line in str
* \returns line, NULL when done */
char *mgcp_strline(char *str, char **saveptr)
{
char *result;
/*! The function must be called with *str set to the input string
* for the first line. After that saveptr will be initalized.
* all consecutive lines are extracted by calling the function
* with str set to NULL. When done, the function will return NULL
* to indicate that all lines have been parsed. */
if (str)
*saveptr = str;
result = *saveptr;
if (*saveptr != NULL) {
*saveptr = strpbrk(*saveptr, "\r\n");
if (*saveptr != NULL) {
char *eos = *saveptr;
if ((*saveptr)[0] == '\r' && (*saveptr)[1] == '\n')
(*saveptr)++;
(*saveptr)++;
if ((*saveptr)[0] == '\0')
*saveptr = NULL;
*eos = '\0';
}
}
return result;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,699 +0,0 @@
/*
* (C) 2012-2013 by Pablo Neira Ayuso <pablo@gnumonks.org>
* (C) 2012-2013 by On Waves ehf <http://www.on-waves.com>
* All rights not specifically granted under this license are 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.
*/
#include <stdio.h> /* for printf */
#include <string.h> /* for memcpy */
#include <stdlib.h> /* for abs */
#include <inttypes.h> /* for PRIu64 */
#include <netinet/in.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/netif/osmux.h>
#include <osmocom/netif/rtp.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/osmux.h>
#include <osmocom/mgcp/mgcp_conn.h>
static struct osmo_fd osmux_fd;
static LLIST_HEAD(osmux_handle_list);
struct osmux_handle {
struct llist_head head;
struct osmux_in_handle *in;
struct in_addr rem_addr;
int rem_port;
int refcnt;
};
static void *osmux;
/* Deliver OSMUX batch to the remote end */
static void osmux_deliver_cb(struct msgb *batch_msg, void *data)
{
struct osmux_handle *handle = data;
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));
msgb_free(batch_msg);
}
/* Lookup existing OSMUX handle for specified destination address. */
static struct osmux_handle *
osmux_handle_find_get(struct in_addr *addr, int rem_port)
{
struct osmux_handle *h;
llist_for_each_entry(h, &osmux_handle_list, head) {
if (memcmp(&h->rem_addr, addr, sizeof(struct in_addr)) == 0 &&
h->rem_port == rem_port) {
LOGP(DLMGCP, LOGL_DEBUG, "using existing OSMUX handle "
"for addr=%s:%d\n",
inet_ntoa(*addr), ntohs(rem_port));
h->refcnt++;
return h;
}
}
return NULL;
}
/* Put down no longer needed OSMUX handle */
static void osmux_handle_put(struct osmux_in_handle *in)
{
struct osmux_handle *h;
llist_for_each_entry(h, &osmux_handle_list, head) {
if (h->in == in) {
if (--h->refcnt == 0) {
LOGP(DLMGCP, LOGL_INFO,
"Releasing unused osmux handle for %s:%d\n",
inet_ntoa(h->rem_addr),
ntohs(h->rem_port));
LOGP(DLMGCP, LOGL_INFO, "Stats: "
"input RTP msgs: %u bytes: %"PRIu64" "
"output osmux msgs: %u bytes: %"PRIu64"\n",
in->stats.input_rtp_msgs,
in->stats.input_rtp_bytes,
in->stats.output_osmux_msgs,
in->stats.output_osmux_bytes);
llist_del(&h->head);
osmux_xfrm_input_fini(h->in);
talloc_free(h);
}
return;
}
}
LOGP(DLMGCP, LOGL_ERROR, "cannot find Osmux input handle %p\n", in);
}
/* Allocate free OSMUX handle */
static struct osmux_handle *
osmux_handle_alloc(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
{
struct osmux_handle *h;
h = talloc_zero(osmux, struct osmux_handle);
if (!h)
return NULL;
h->rem_addr = *addr;
h->rem_port = rem_port;
h->refcnt++;
h->in = talloc_zero(h, struct osmux_in_handle);
if (!h->in) {
talloc_free(h);
return NULL;
}
/* sequence number to start OSMUX message from */
h->in->osmux_seq = 0;
h->in->batch_factor = cfg->osmux_batch;
/* If batch size is zero, the library defaults to 1470 bytes. */
h->in->batch_size = cfg->osmux_batch_size;
h->in->deliver = osmux_deliver_cb;
osmux_xfrm_input_init(h->in);
h->in->data = h;
llist_add(&h->head, &osmux_handle_list);
LOGP(DLMGCP, LOGL_DEBUG, "created new OSMUX handle for addr=%s:%d\n",
inet_ntoa(*addr), ntohs(rem_port));
return h;
}
/* Lookup existing handle for a specified address, if the handle can not be
* foud a the function will automatically allocate one */
static struct osmux_in_handle *
osmux_handle_lookup(struct mgcp_config *cfg, struct in_addr *addr, int rem_port)
{
struct osmux_handle *h;
h = osmux_handle_find_get(addr, rem_port);
if (h != NULL)
return h->in;
h = osmux_handle_alloc(cfg, addr, rem_port);
if (h == NULL)
return NULL;
return h->in;
}
/*! send RTP packet through OSMUX connection.
* \param[in] buf rtp data
* \param[in] buf_len length of rtp data
* \param[in] conn associated RTP connection
* \returns 0 on success, -1 on ERROR */
int osmux_xfrm_to_osmux(char *buf, int buf_len, struct mgcp_conn_rtp *conn)
{
int ret;
struct msgb *msg;
msg = msgb_alloc(4096, "RTP");
if (!msg)
return -1;
memcpy(msg->data, buf, buf_len);
msgb_put(msg, buf_len);
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);
}
return 0;
}
/* Lookup the endpoint that corresponds to the specified address (port) */
static struct mgcp_endpoint *
endpoint_lookup(struct mgcp_config *cfg, int cid,
struct in_addr *from_addr, int type)
{
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<cfg->trunk.number_endpoints; i++) {
struct in_addr *this;
endp = &cfg->trunk.endpoints[i];
#if 0
if (!tmp->allocated)
continue;
#endif
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 endpoint with cid=%d\n", cid);
return NULL;
}
static void scheduled_tx_net_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_net->end.addr,
.sin_port = conn_net->end.rtp_port,
};
conn_bts->end.octets_tx += msg->len;
conn_bts->end.packets_tx++;
/* Send RTP data to NET */
/* FIXME: Get rid of conn_bts and conn_net! */
mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
conn_bts, conn_net);
msgb_free(msg);
}
static void scheduled_tx_bts_cb(struct msgb *msg, void *data)
{
struct mgcp_endpoint *endp = data;
struct mgcp_conn_rtp *conn_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,
};
conn_net->end.octets_tx += msg->len;
conn_net->end.packets_tx++;
/* Send RTP data to BTS */
/* FIXME: Get rid of conn_bts and conn_net! */
mgcp_send(endp, 1, &addr, (char *)msg->data, msg->len,
conn_net, conn_bts);
msgb_free(msg);
}
static struct msgb *osmux_recv(struct osmo_fd *ofd, struct sockaddr_in *addr)
{
struct msgb *msg;
socklen_t slen = sizeof(*addr);
int ret;
msg = msgb_alloc(4096, "OSMUX");
if (!msg) {
LOGP(DLMGCP, LOGL_ERROR, "cannot allocate message\n");
return NULL;
}
ret = recvfrom(ofd->fd, msg->data, msg->data_len, 0,
(struct sockaddr *)addr, &slen);
if (ret <= 0) {
msgb_free(msg);
LOGP(DLMGCP, LOGL_ERROR, "cannot receive message\n");
return NULL;
}
msgb_put(msg, ret);
return msg;
}
#define osmux_chunk_length(msg, rem) (rem - msg->len);
int osmux_read_from_bsc_nat_cb(struct osmo_fd *ofd, unsigned int what)
{
struct msgb *msg;
struct osmux_hdr *osmuxh;
struct llist_head list;
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;
/* not any further processing dummy messages */
if (msg->data[0] == MGCP_DUMMY_LOAD)
goto out;
rem = msg->len;
while((osmuxh = osmux_xfrm_output_pull(msg)) != NULL) {
struct mgcp_endpoint *endp;
/* 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_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
if (!conn_net)
goto out;
if (!endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find an endpoint for circuit_id=%d\n",
osmuxh->circuit_id);
goto out;
}
conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
conn_net->osmux.stats.chunks++;
rem = msg->len;
osmux_xfrm_output(osmuxh, &conn_net->osmux.out, &list);
osmux_tx_sched(&list, scheduled_tx_bts_cb, endp);
}
out:
msgb_free(msg);
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)
{
struct mgcp_endpoint *endp;
uint8_t osmux_cid;
struct mgcp_conn_rtp *conn_net = NULL;
if (msg->len < 1 + sizeof(osmux_cid)) {
LOGP(DLMGCP, LOGL_ERROR,
"Discarding truncated Osmux dummy load\n");
goto out;
}
LOGP(DLMGCP, LOGL_DEBUG, "Received Osmux dummy load from %s\n",
inet_ntoa(addr->sin_addr));
if (!cfg->osmux) {
LOGP(DLMGCP, LOGL_ERROR,
"bsc wants to use Osmux but bsc-nat did not request it\n");
goto out;
}
/* extract the osmux CID from the dummy message */
memcpy(&osmux_cid, &msg->data[1], sizeof(osmux_cid));
endp = endpoint_lookup(cfg, osmux_cid, &addr->sin_addr, MGCP_DEST_BTS);
if (!endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find endpoint for Osmux CID %d\n", osmux_cid);
goto out;
}
conn_net = mgcp_conn_get_rtp(endp, CONN_ID_NET);
if (!conn_net)
goto out;
if (conn_net->osmux.state == OSMUX_STATE_ENABLED)
goto out;
if (osmux_enable_conn(endp, conn_net, &addr->sin_addr, addr->sin_port) < 0 ) {
LOGP(DLMGCP, LOGL_ERROR,
"Could not enable osmux in endpoint %d\n",
ENDPOINT_NUMBER(endp));
goto out;
}
LOGP(DLMGCP, LOGL_INFO, "Enabling osmux in endpoint %d for %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr),
ntohs(addr->sin_port));
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 llist_head list;
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;
/* not any further processing dummy messages */
if (msg->data[0] == MGCP_DUMMY_LOAD)
return osmux_handle_dummy(cfg, &addr, msg);
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)
goto out;
if (!endp) {
LOGP(DLMGCP, LOGL_ERROR,
"Cannot find an endpoint for circuit_id=%d\n",
osmuxh->circuit_id);
goto out;
}
conn_net->osmux.stats.octets += osmux_chunk_length(msg, rem);
conn_net->osmux.stats.chunks++;
rem = msg->len;
osmux_xfrm_output(osmuxh, &conn_net->osmux.out, &list);
osmux_tx_sched(&list, scheduled_tx_net_cb, endp);
}
out:
msgb_free(msg);
return 0;
}
int osmux_init(int role, struct mgcp_config *cfg)
{
int ret;
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);
if (ret < 0) {
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\n");
return ret;
}
cfg->osmux_init = 1;
return 0;
}
/*! enable OSXMUX circuit for a specified connection.
* \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
* \returns 0 on success, -1 on ERROR */
int osmux_enable_conn(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn,
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
* allocated based on the circuit ID (conn_net->osmux.cid), which is unique
* in the local scope to the BSC/BSC-NAT. We use it to divide the RTP
* SSRC space (2^32) by the 256 possible circuit IDs, then randomly
* select one value from that window. Thus, we have no chance to have
* overlapping RTP SSRC traveling to the BTSes behind the BSC,
* similarly, for flows traveling to the MSC.
*/
static const uint32_t rtp_ssrc_winlen = UINT32_MAX / 256;
uint16_t osmux_dummy = endp->cfg->osmux_dummy;
/* Check if osmux is enabled for the specified connection */
if (conn->osmux.state == OSMUX_STATE_DISABLED) {
LOGP(DLMGCP, LOGL_ERROR, "OSMUX not enabled for conn:%s\n",
mgcp_conn_dump(conn->conn));
return -1;
}
osmux_xfrm_output_init(&conn->osmux.out,
(conn->osmux.cid * rtp_ssrc_winlen) +
(random() % rtp_ssrc_winlen));
conn->osmux.in = osmux_handle_lookup(endp->cfg, addr, port);
if (!conn->osmux.in) {
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)) {
LOGP(DLMGCP, LOGL_ERROR, "Cannot open osmux circuit %u for conn:%s\n",
conn->osmux.cid, mgcp_conn_dump(conn->conn));
return -1;
}
switch (endp->cfg->role) {
case MGCP_BSC_NAT:
conn->type = MGCP_OSMUX_BSC_NAT;
break;
case MGCP_BSC:
conn->type = MGCP_OSMUX_BSC;
break;
}
conn->osmux.state = OSMUX_STATE_ENABLED;
return 0;
}
/*! disable OSXMUX circuit for a specified connection.
* \param[in] conn connection to disable */
void osmux_disable_conn(struct mgcp_conn_rtp *conn)
{
if (!conn)
return;
if (conn->osmux.state != OSMUX_STATE_ENABLED)
return;
LOGP(DLMGCP, LOGL_INFO, "Releasing connection %s using Osmux CID %u\n",
conn->conn->id, conn->osmux.cid);
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 osmux_release_cid(struct mgcp_conn_rtp *conn)
{
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*/
void osmux_allocate_cid(struct mgcp_conn_rtp *conn)
{
osmux_release_cid(conn);
conn->osmux.allocated_cid = osmux_get_cid();
}
/*! send RTP dummy packet to OSMUX connection port.
* \param[in] endp mcgp endpoint that holds the RTP connection
* \param[in] conn associated RTP connection
* \returns bytes sent, -1 on error */
int osmux_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
{
char buf[1 + sizeof(uint8_t)];
struct in_addr addr_unset = {};
/*! The dummy packet will not be sent via the actual OSMUX connection,
* instead it is sent out of band to port where the remote OSMUX
* multplexer is listening. The goal is to ensure that the connection
* is kept open */
/*! We don't need to send the dummy load for osmux so often as another
* 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;
if (conn->osmux.state == OSMUX_STATE_ACTIVATING) {
if (osmux_enable_conn(endp, conn, &conn->end.addr,
htons(endp->cfg->osmux_port)) < 0) {
LOGP(DLMGCP, LOGL_ERROR,
"Could not activate osmux for conn:%s\n",
mgcp_conn_dump(conn->conn));
}
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);
}
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,
htons(endp->cfg->osmux_port), buf, sizeof(buf));
}
/*! bsc-nat allocates/releases the OSMUX cids (Circuit IDs). */
static uint8_t osmux_cid_bitmap[(OSMUX_CID_MAX + 1) / 8];
/*! count the number of taken OSMUX cids.
* \returns number of OSMUX cids in use */
int osmux_used_cid(void)
{
int i, j, used = 0;
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
for (j = 0; j < 8; j++) {
if (osmux_cid_bitmap[i] & (1 << j))
used += 1;
}
}
return used;
}
/*! take a free OSMUX cid.
* \returns OSMUX cid */
int osmux_get_cid(void)
{
int i, j;
for (i = 0; i < sizeof(osmux_cid_bitmap); i++) {
for (j = 0; j < 8; j++) {
if (osmux_cid_bitmap[i] & (1 << j))
continue;
osmux_cid_bitmap[i] |= (1 << j);
LOGP(DLMGCP, LOGL_DEBUG,
"Allocating Osmux CID %u from pool\n", (i * 8) + j);
return (i * 8) + j;
}
}
LOGP(DLMGCP, LOGL_ERROR, "All Osmux circuits are in use!\n");
return -1;
}
/*! put back a no longer used OSMUX cid.
* \param[in] osmux_cid 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));
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,409 +0,0 @@
/*
* Some SDP file parsing...
*
* (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2014 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/>.
*
*/
#include <osmocom/core/msgb.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/mgcp_msg.h>
#include <errno.h>
struct sdp_rtp_map {
/* the type */
int payload_type;
/* null, static or later dynamic codec name */
char *codec_name;
/* A pointer to the original line for later parsing */
char *map_line;
int rate;
int channels;
};
/*! Set codec configuration depending on payload type and codec name.
* \param[in] ctx talloc context.
* \param[out] codec configuration (caller provided memory).
* \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, -1 on failure. */
int mgcp_set_audio_info(void *ctx, struct mgcp_rtp_codec *codec,
int payload_type, const char *audio_name)
{
int rate = codec->rate;
int channels = codec->channels;
char audio_codec[64];
talloc_free(codec->subtype_name);
codec->subtype_name = NULL;
talloc_free(codec->audio_name);
codec->audio_name = NULL;
if (payload_type != PTYPE_UNDEFINED)
codec->payload_type = payload_type;
if (!audio_name) {
switch (payload_type) {
case 0:
audio_name = "PCMU/8000/1";
break;
case 3:
audio_name = "GSM/8000/1";
break;
case 8:
audio_name = "PCMA/8000/1";
break;
case 18:
audio_name = "G729/8000/1";
break;
default:
/* Payload type is unknown, don't change rate and
* channels. */
/* TODO: return value? */
return 0;
}
}
if (sscanf(audio_name, "%63[^/]/%d/%d",
audio_codec, &rate, &channels) < 1)
return -EINVAL;
codec->rate = rate;
codec->channels = channels;
codec->subtype_name = talloc_strdup(ctx, audio_codec);
codec->audio_name = talloc_strdup(ctx, audio_name);
if (!strcmp(audio_codec, "G729")) {
codec->frame_duration_num = 10;
codec->frame_duration_den = 1000;
} else {
codec->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM;
codec->frame_duration_den = DEFAULT_RTP_AUDIO_FRAME_DUR_DEN;
}
if (payload_type < 0) {
payload_type = 96;
if (rate == 8000 && channels == 1) {
if (!strcmp(audio_codec, "GSM"))
payload_type = 3;
else if (!strcmp(audio_codec, "PCMA"))
payload_type = 8;
else if (!strcmp(audio_codec, "PCMU"))
payload_type = 0;
else if (!strcmp(audio_codec, "G729"))
payload_type = 18;
}
codec->payload_type = payload_type;
}
if (channels != 1)
LOGP(DLMGCP, LOGL_NOTICE,
"Channels != 1 in SDP: '%s'\n", audio_name);
return 0;
}
static void codecs_initialize(void *ctx, struct sdp_rtp_map *codecs, int used)
{
int i;
for (i = 0; i < used; ++i) {
switch (codecs[i].payload_type) {
case 0:
codecs[i].codec_name = "PCMU";
codecs[i].rate = 8000;
codecs[i].channels = 1;
break;
case 3:
codecs[i].codec_name = "GSM";
codecs[i].rate = 8000;
codecs[i].channels = 1;
break;
case 8:
codecs[i].codec_name = "PCMA";
codecs[i].rate = 8000;
codecs[i].channels = 1;
break;
case 18:
codecs[i].codec_name = "G729";
codecs[i].rate = 8000;
codecs[i].channels = 1;
break;
}
}
}
static void codecs_update(void *ctx, struct sdp_rtp_map *codecs, int used,
int payload, const char *audio_name)
{
int i;
for (i = 0; i < used; ++i) {
char audio_codec[64];
int rate = -1;
int channels = -1;
if (codecs[i].payload_type != payload)
continue;
if (sscanf(audio_name, "%63[^/]/%d/%d",
audio_codec, &rate, &channels) < 1) {
LOGP(DLMGCP, LOGL_ERROR, "Failed to parse '%s'\n",
audio_name);
continue;
}
codecs[i].map_line = talloc_strdup(ctx, audio_name);
codecs[i].codec_name = talloc_strdup(ctx, audio_codec);
codecs[i].rate = rate;
codecs[i].channels = channels;
return;
}
LOGP(DLMGCP, LOGL_ERROR, "Unconfigured PT(%d) with %s\n", payload,
audio_name);
}
/* Check if the codec matches what is set up in the trunk config */
static int is_codec_compatible(const struct mgcp_endpoint *endp,
const struct sdp_rtp_map *codec)
{
char *codec_str;
char audio_codec[64];
if (!codec->codec_name)
return 0;
/* GSM, GSM/8000 and GSM/8000/1 should all be compatible...
* let's go by name first. */
codec_str = endp->tcfg->audio_name;
if (sscanf(codec_str, "%63[^/]/%*d/%*d", audio_codec) < 1)
return 0;
return strcasecmp(audio_codec, codec->codec_name) == 0;
}
/*! Analyze SDP input string.
* \param[in] endp trunk endpoint.
* \param[out] conn associated rtp connection.
* \param[out] caller provided memory to store the parsing results.
* \returns 0 on success, -1 on failure.
*
* Note: In conn (conn->end) the function returns the packet duration,
* the rtp port and the rtcp port */
int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp,
struct mgcp_conn_rtp *conn,
struct mgcp_parse_data *p)
{
struct sdp_rtp_map codecs[10];
int codecs_used = 0;
char *line;
int maxptime = -1;
int i;
int codecs_assigned = 0;
void *tmp_ctx = talloc_new(NULL);
struct mgcp_rtp_end *rtp;
int payload;
int ptime, ptime2 = 0;
char audio_name[64];
int port, rc;
char ipv4[16];
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
OSMO_ASSERT(p);
rtp = &conn->end;
memset(&codecs, 0, sizeof(codecs));
for_each_line(line, p->save) {
switch (line[0]) {
case 'o':
case 's':
case 't':
case 'v':
/* 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);
} 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;
} else if (sscanf(line, "a=maxptime:%d", &ptime2)
== 1) {
maxptime = ptime2;
}
break;
case 'm':
rc = sscanf(line,
"m=audio %d RTP/AVP %d %d %d %d %d %d %d %d %d %d",
&port, &codecs[0].payload_type,
&codecs[1].payload_type,
&codecs[2].payload_type,
&codecs[3].payload_type,
&codecs[4].payload_type,
&codecs[5].payload_type,
&codecs[6].payload_type,
&codecs[7].payload_type,
&codecs[8].payload_type,
&codecs[9].payload_type);
if (rc >= 2) {
rtp->rtp_port = htons(port);
rtp->rtcp_port = htons(port + 1);
codecs_used = rc - 1;
codecs_initialize(tmp_ctx, codecs, codecs_used);
}
break;
case 'c':
if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
inet_aton(ipv4, &rtp->addr);
}
break;
default:
if (p->endp)
LOGP(DLMGCP, LOGL_NOTICE,
"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",
line[0], line[0]);
break;
}
}
/* Now select the primary and alt_codec */
for (i = 0; i < codecs_used && codecs_assigned < 2; ++i) {
struct mgcp_rtp_codec *codec = codecs_assigned == 0 ?
&rtp->codec : &rtp->alt_codec;
if (endp->tcfg->no_audio_transcoding &&
!is_codec_compatible(endp, &codecs[i])) {
LOGP(DLMGCP, LOGL_NOTICE, "Skipping codec %s\n",
codecs[i].codec_name);
continue;
}
mgcp_set_audio_info(p->cfg, codec,
codecs[i].payload_type, codecs[i].map_line);
codecs_assigned += 1;
}
if (codecs_assigned > 0) {
/* TODO/XXX: Store this per codec and derive it on use */
if (maxptime >= 0 && maxptime * rtp->codec.frame_duration_den >
rtp->codec.frame_duration_num * 1500) {
/* more than 1 frame */
rtp->packet_duration_ms = 0;
}
LOGP(DLMGCP, LOGL_NOTICE,
"Got media info via SDP: port %d, payload %d (%s), "
"duration %d, addr %s\n",
ntohs(rtp->rtp_port), rtp->codec.payload_type,
rtp->codec.subtype_name ? rtp->
codec.subtype_name : "unknown", rtp->packet_duration_ms,
inet_ntoa(rtp->addr));
}
talloc_free(tmp_ctx);
return codecs_assigned > 0;
}
/*! Generate SDP response string.
* \param[in] endp trunk endpoint.
* \param[in] conn associated rtp connection.
* \param[out] sdp msg buffer to append resulting SDP string data.
* \param[in] addr IPV4 address string (e.g. 192.168.100.1).
* \returns 0 on success, -1 on failure. */
int mgcp_write_response_sdp(const struct mgcp_endpoint *endp,
const struct mgcp_conn_rtp *conn, struct msgb *sdp,
const char *addr)
{
const char *fmtp_extra;
const char *audio_name;
int payload_type;
int rc;
OSMO_ASSERT(endp);
OSMO_ASSERT(conn);
OSMO_ASSERT(sdp);
OSMO_ASSERT(addr);
/* FIXME: constify endp and conn args in get_net_donwlink_format_cb() */
endp->cfg->get_net_downlink_format_cb((struct mgcp_endpoint *)endp,
&payload_type, &audio_name,
&fmtp_extra,
(struct mgcp_conn_rtp *)conn);
rc = msgb_printf(sdp,
"v=0\r\n"
"o=- %s 23 IN IP4 %s\r\n"
"s=-\r\n"
"c=IN IP4 %s\r\n"
"t=0 0\r\n", conn->conn->id, addr, addr);
if (rc < 0)
goto buffer_too_small;
if (payload_type >= 0) {
rc = msgb_printf(sdp, "m=audio %d RTP/AVP %d\r\n",
conn->end.local_port, payload_type);
if (rc < 0)
goto buffer_too_small;
if (audio_name && endp->tcfg->audio_send_name) {
rc = msgb_printf(sdp, "a=rtpmap:%d %s\r\n",
payload_type, audio_name);
if (rc < 0)
goto buffer_too_small;
}
if (fmtp_extra) {
rc = msgb_printf(sdp, "%s\r\n", fmtp_extra);
if (rc < 0)
goto buffer_too_small;
}
}
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)
goto buffer_too_small;
}
return 0;
buffer_too_small:
LOGP(DLMGCP, LOGL_ERROR, "SDP messagebuffer too small\n");
return -1;
}

View File

@@ -1,128 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* The statistics generator */
/*
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2012 by On-Waves
* (C) 2017 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_stat.h>
#include <limits.h>
/* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
void calc_loss(struct mgcp_rtp_state *state,
struct mgcp_rtp_end *end, uint32_t *expected,
int *loss)
{
*expected = state->stats_cycles + state->stats_max_seq;
*expected = *expected - state->stats_base_seq + 1;
if (!state->stats_initialized) {
*expected = 0;
*loss = 0;
return;
}
/*
* Make sure the sign is correct and use the biggest
* positive/negative number that fits.
*/
*loss = *expected - end->packets_rx;
if (*expected < end->packets_rx) {
if (*loss > 0)
*loss = INT_MIN;
} else {
if (*loss < 0)
*loss = INT_MAX;
}
}
/* Helper function for mgcp_format_stats_rtp() to calculate jitter */
uint32_t calc_jitter(struct mgcp_rtp_state *state)
{
if (!state->stats_initialized)
return 0;
return state->stats_jitter >> 4;
}
/* Generate statistics for an RTP connection */
static void mgcp_format_stats_rtp(char *str, size_t str_len,
struct mgcp_conn_rtp *conn)
{
uint32_t expected, jitter;
int ploss;
int nchars;
calc_loss(&conn->state, &conn->end, &expected, &ploss);
jitter = calc_jitter(&conn->state);
nchars = snprintf(str, str_len,
"\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
conn->end.packets_tx, conn->end.octets_tx,
conn->end.packets_rx, conn->end.octets_rx,
ploss, jitter);
if (nchars < 0 || nchars >= str_len)
goto truncate;
str += nchars;
str_len -= nchars;
/* Error Counter */
nchars = snprintf(str, str_len,
"\r\nX-Osmo-CP: EC TI=%u, TO=%u",
conn->state.in_stream.err_ts_counter,
conn->state.out_stream.err_ts_counter);
if (nchars < 0 || nchars >= str_len)
goto truncate;
str += nchars;
str_len -= nchars;
if (conn->osmux.state == OSMUX_STATE_ENABLED) {
snprintf(str, str_len,
"\r\nX-Osmux-ST: CR=%u, BR=%u",
conn->osmux.stats.chunks, conn->osmux.stats.octets);
}
truncate:
str[str_len - 1] = '\0';
}
/*! format statistics into an mgcp parameter string.
* \param[out] str resulting string
* \param[in] str_len length of the string buffer
* \param[in] conn connection to evaluate */
void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn)
{
memset(str, 0, str_len);
if (!conn)
return;
/* NOTE: At the moment we only support generating statistics for
* RTP connections. However, in the future we may also want to
* generate statistics for other connection types as well. Lets
* keep this option open: */
switch (conn->type) {
case MGCP_CONN_TYPE_RTP:
mgcp_format_stats_rtp(str, str_len, &conn->u.rtp);
break;
default:
break;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(LIBBCG729_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
@@ -23,6 +24,7 @@ osmo_bsc_mgcp_SOURCES = \
osmo_bsc_mgcp_LDADD = \
$(top_builddir)/src/libosmo-legacy-mgcp/libosmo-legacy-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBBCG729_LIBS) \
$(LIBRARY_GSM) \

View File

@@ -189,33 +189,33 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what)
int mgcp_vty_is_config_node(struct vty *vty, int node)
{
switch (node) {
case CONFIG_NODE:
return 0;
switch (node) {
case CONFIG_NODE:
return 0;
default:
return 1;
}
default:
return 1;
}
}
int mgcp_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case TRUNK_NODE:
vty->node = MGCP_NODE;
vty->index = NULL;
break;
case MGCP_NODE:
default:
if (mgcp_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;
else
vty->node = ENABLE_NODE;
switch (vty->node) {
case TRUNK_NODE:
vty->node = MGCP_NODE;
vty->index = NULL;
break;
case MGCP_NODE:
default:
if (mgcp_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;
else
vty->node = ENABLE_NODE;
vty->index = NULL;
}
vty->index = NULL;
}
return vty->node;
return vty->node;
}
@@ -231,8 +231,8 @@ static const struct log_info_cat log_categories[] = {
};
const struct log_info log_info = {
.cat = log_categories,
.num_cat = ARRAY_SIZE(log_categories),
.cat = log_categories,
.num_cat = ARRAY_SIZE(log_categories),
};
int main(int argc, char **argv)
@@ -256,8 +256,6 @@ int main(int argc, char **argv)
cfg->get_net_downlink_format_cb = &mgcp_transcoding_net_downlink_format;
#endif
cfg->trunk.force_realloc = 1;
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
@@ -282,8 +280,8 @@ int main(int argc, char **argv)
/* set some callbacks */
cfg->reset_cb = mgcp_rsip_cb;
/* we need to bind a socket */
if (rc == 0) {
/* we need to bind a socket */
if (rc == 0) {
cfg->gw_fd.bfd.when = BSC_FD_READ;
cfg->gw_fd.bfd.cb = read_call_agent;
cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);

View File

@@ -1,26 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
bin_PROGRAMS = \
osmo-mgw \
$(NULL)
osmo_mgw_SOURCES = \
mgw_main.c \
$(NULL)
osmo_mgw_LDADD = \
$(top_builddir)/src/libosmo-mgcp/libosmo-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(NULL)

View File

@@ -1,332 +0,0 @@
/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
/* The main method to drive it as a standalone process */
/*
* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
* (C) 2017 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier
* 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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <osmocom/mgcp/mgcp.h>
#include <osmocom/mgcp/mgcp_internal.h>
#include <osmocom/mgcp/vty.h>
#include <osmocom/mgcp/debug.h>
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/socket.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 "../../bscconfig.h"
#define _GNU_SOURCE
#include <getopt.h>
/* FIXME: Make use of the rtp proxy code */
static struct mgcp_config *cfg;
static struct mgcp_trunk_config *reset_trunk;
static int reset_endpoints = 0;
static int daemonize = 0;
const char *osmomgw_copyright =
"Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
"Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
"Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
"Philipp Maier\r\n\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
static char *config_file = "osmo-mgw.cfg";
/* used by msgb and mgcp */
void *tall_bsc_ctx = NULL;
static void print_help()
{
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");
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
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'},
{0, 0, 0, 0},
};
c = getopt_long(argc, argv, "hc:VD", long_options, &option_index);
if (c == -1)
break;
switch(c) {
case 'h':
print_help();
exit(0);
break;
case 'c':
config_file = talloc_strdup(tall_bsc_ctx, optarg);
break;
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
case 'V':
print_version(1);
exit(0);
break;
case 'D':
daemonize = 1;
break;
default:
/* ignore */
break;
};
}
}
/* Callback function to be called when the RSIP ("Reset in Progress") mgcp
* command is received */
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 = tcfg;
return 0;
}
static int read_call_agent(struct osmo_fd *fd, unsigned int what)
{
struct sockaddr_in addr;
socklen_t slen = sizeof(addr);
struct msgb *msg;
struct msgb *resp;
int i;
msg = (struct msgb *) fd->data;
/* read one less so we can use it as a \0 */
int rc = recvfrom(cfg->gw_fd.bfd.fd, msg->data, msg->data_len - 1, 0,
(struct sockaddr *) &addr, &slen);
if (rc < 0) {
perror("Gateway failed to read");
return -1;
} else if (slen > sizeof(addr)) {
fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n",
(size_t) slen, sizeof(addr));
return -1;
}
/* handle message now */
msg->l2h = msgb_put(msg, rc);
resp = mgcp_handle_message(cfg, msg);
msgb_reset(msg);
if (resp) {
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: %d/%d\n",
reset_trunk->trunk_nr, reset_trunk->trunk_type);
/* reset flag */
reset_endpoints = 0;
/* Walk over all endpoints and trigger a release, this will release all
* endpoints, possible open connections are forcefully dropped */
for (i = 1; i < reset_trunk->number_endpoints; ++i)
mgcp_release_endp(&reset_trunk->endpoints[i]);
}
return 0;
}
int mgcp_vty_is_config_node(struct vty *vty, int node)
{
switch (node) {
case CONFIG_NODE:
return 0;
default:
return 1;
}
}
int mgcp_vty_go_parent(struct vty *vty)
{
switch (vty->node) {
case TRUNK_NODE:
vty->node = MGCP_NODE;
vty->index = NULL;
break;
case MGCP_NODE:
default:
if (mgcp_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;
else
vty->node = ENABLE_NODE;
vty->index = NULL;
}
return vty->node;
}
static struct vty_app_info vty_info = {
.name = "OsmoMGW",
.version = PACKAGE_VERSION,
.go_parent_cb = mgcp_vty_go_parent,
.is_config_node = mgcp_vty_is_config_node,
};
static const struct log_info_cat log_categories[] = {
/* DLMGCP is provided by the MGCP library */
[DRTP] = {
.name = "DRTP",
.description = "RTP stream handling",
.color = "\033[1;30m",
.enabled = 1,.loglevel = LOGL_NOTICE,
},
};
const struct log_info log_info = {
.cat = log_categories,
.num_cat = ARRAY_SIZE(log_categories),
};
int main(int argc, char **argv)
{
unsigned int flags;
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
msgb_talloc_ctx_init(tall_bsc_ctx, 0);
osmo_init_ignore_signals();
osmo_init_logging(&log_info);
cfg = mgcp_config_alloc();
if (!cfg)
return -1;
vty_info.copyright = osmomgw_copyright;
vty_init(&vty_info);
logging_vty_add_cmds(NULL);
osmo_stats_vty_add_cmds(&log_info);
mgcp_vty_init();
handle_options(argc, argv);
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_bsc_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
if (rc < 0)
return rc;
/* 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 (cfg->call_agent_addr)
flags |= OSMO_SOCK_F_CONNECT;
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, cfg->call_agent_addr ? 2727 : 0, flags);
if (rc < 0) {
perror("Gateway failed to bind");
return -1;
}
cfg->gw_fd.bfd.cb = read_call_agent;
cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
if (!cfg->gw_fd.bfd.data) {
fprintf(stderr, "Gateway memory error.\n");
return -1;
}
LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
/* initialisation */
srand(time(NULL));
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
perror("Error during daemonize");
exit(1);
}
}
/* main loop */
while (1) {
osmo_select_main(0);
}
return 0;
}

View File

@@ -1,7 +1,5 @@
SUBDIRS = \
legacy_mgcp \
mgcp_client \
mgcp \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
@@ -27,6 +25,7 @@ EXTRA_DIST = \
$(srcdir)/package.m4 \
$(TESTSUITE) \
vty_test_runner.py \
ctrl_test_runner.py \
$(NULL)
TESTSUITE = $(srcdir)/testsuite
@@ -40,6 +39,7 @@ python-tests: $(BUILT_SOURCES)
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
$(PYTHON) $(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
$(PYTHON) $(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
else
python-tests: $(BUILT_SOURCES)
echo "Not running python-based tests (determined at configure-time)"

575
tests/ctrl_test_runner.py Normal file
View File

@@ -0,0 +1,575 @@
#!/usr/bin/env python
# (C) 2013 by Jacob Erlbeck <jerlbeck@sysmocom.de>
# (C) 2014 by Holger Hans Peter Freyther
# based on vty_test_runner.py:
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
# (C) 2013 by Holger Hans Peter Freyther
# based on bsc_control.py.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import time
import unittest
import socket
import sys
import struct
import osmopy.obscvty as obscvty
import osmopy.osmoutil as osmoutil
# add $top_srcdir/contrib to find ipa.py
sys.path.append(os.path.join(sys.path[0], '..', 'contrib'))
from ipa import Ctrl, IPA
# to be able to find $top_srcdir/doc/...
confpath = os.path.join(sys.path[0], '..')
verbose = False
class TestCtrlBase(unittest.TestCase):
def ctrl_command(self):
raise Exception("Needs to be implemented by a subclass")
def ctrl_app(self):
raise Exception("Needs to be implemented by a subclass")
def setUp(self):
osmo_ctrl_cmd = self.ctrl_command()[:]
config_index = osmo_ctrl_cmd.index('-c')
if config_index:
cfi = config_index + 1
osmo_ctrl_cmd[cfi] = os.path.join(confpath, osmo_ctrl_cmd[cfi])
try:
self.proc = osmoutil.popen_devnull(osmo_ctrl_cmd)
except OSError:
print >> sys.stderr, "Current directory: %s" % os.getcwd()
print >> sys.stderr, "Consider setting -b"
time.sleep(2)
appstring = self.ctrl_app()[2]
appport = self.ctrl_app()[0]
self.connect("127.0.0.1", appport)
self.next_id = 1000
def tearDown(self):
self.disconnect()
osmoutil.end_proc(self.proc)
def disconnect(self):
if not (self.sock is None):
self.sock.close()
def connect(self, host, port):
if verbose:
print "Connecting to host %s:%i" % (host, port)
retries = 30
while True:
try:
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setblocking(1)
sck.connect((host, port))
except IOError:
retries -= 1
if retries <= 0:
raise
time.sleep(.1)
continue
break
self.sock = sck
return sck
def send(self, data):
if verbose:
print "Sending \"%s\"" %(data)
data = Ctrl().add_header(data)
return self.sock.send(data) == len(data)
def send_set(self, var, value, id):
setmsg = "SET %s %s %s" %(id, var, value)
return self.send(setmsg)
def send_get(self, var, id):
getmsg = "GET %s %s" %(id, var)
return self.send(getmsg)
def do_set(self, var, value):
id = self.next_id
self.next_id += 1
self.send_set(var, value, id)
return self.recv_msgs()[id]
def do_get(self, var):
id = self.next_id
self.next_id += 1
self.send_get(var, id)
return self.recv_msgs()[id]
def recv_msgs(self):
responses = {}
data = self.sock.recv(4096)
while (len(data)>0):
(head, data) = IPA().split_combined(data)
answer = Ctrl().rem_header(head)
if verbose:
print "Got message:", answer
(mtype, id, msg) = answer.split(None, 2)
id = int(id)
rsp = {'mtype': mtype, 'id': id}
if mtype == "ERROR":
rsp['error'] = msg
else:
split = msg.split(None, 1)
rsp['var'] = split[0]
if len(split) > 1:
rsp['value'] = split[1]
else:
rsp['value'] = None
responses[id] = rsp
if verbose:
print "Decoded replies: ", responses
return responses
class TestCtrlBSC(TestCtrlBase):
def tearDown(self):
TestCtrlBase.tearDown(self)
os.unlink("tmp_dummy_sock")
def ctrl_command(self):
return ["./src/osmo-bsc/osmo-bsc", "-r", "tmp_dummy_sock", "-c",
"doc/examples/osmo-bsc/osmo-bsc.cfg"]
def ctrl_app(self):
return (4249, "./src/osmo-bsc/osmo-bsc", "OsmoBSC", "bsc")
def testCtrlErrs(self):
r = self.do_get('invalid')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Command not found')
r = self.do_set('rf_locked', '999')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Value failed verification.')
r = self.do_get('bts')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Error while parsing the index.')
r = self.do_get('bts.999')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Error while resolving object')
def testBtsLac(self):
r = self.do_get('bts.0.location-area-code')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.location-area-code')
self.assertEquals(r['value'], '1')
r = self.do_set('bts.0.location-area-code', '23')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.location-area-code')
self.assertEquals(r['value'], '23')
r = self.do_get('bts.0.location-area-code')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.location-area-code')
self.assertEquals(r['value'], '23')
r = self.do_set('bts.0.location-area-code', '-1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Input not within the range')
def testBtsCi(self):
r = self.do_get('bts.0.cell-identity')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.cell-identity')
self.assertEquals(r['value'], '0')
r = self.do_set('bts.0.cell-identity', '23')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.cell-identity')
self.assertEquals(r['value'], '23')
r = self.do_get('bts.0.cell-identity')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.cell-identity')
self.assertEquals(r['value'], '23')
r = self.do_set('bts.0.cell-identity', '-1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Input not within the range')
def testBtsGenerateSystemInformation(self):
r = self.do_get('bts.0.send-new-system-informations')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Write Only attribute')
# No RSL links so it will fail
r = self.do_set('bts.0.send-new-system-informations', '1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Failed to generate SI')
def testBtsChannelLoad(self):
r = self.do_set('bts.0.channel-load', '1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Read Only attribute')
# No RSL link so everything is 0
r = self.do_get('bts.0.channel-load')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['value'],
'CCCH+SDCCH4,0,0 TCH/F,0,0 TCH/H,0,0 SDCCH8,0,0'
+ ' TCH/F_PDCH,0,0 CCCH+SDCCH4+CBCH,0,0'
+ ' SDCCH8+CBCH,0,0 TCH/F_TCH/H_PDCH,0,0')
def testBtsOmlConnectionState(self):
"""Check OML state. It will not be connected"""
r = self.do_set('bts.0.oml-connection-state', '1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Read Only attribute')
# No RSL link so everything is 0
r = self.do_get('bts.0.oml-connection-state')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['value'], 'disconnected')
def testTrxPowerRed(self):
r = self.do_get('bts.0.trx.0.max-power-reduction')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.max-power-reduction')
self.assertEquals(r['value'], '20')
r = self.do_set('bts.0.trx.0.max-power-reduction', '22')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.max-power-reduction')
self.assertEquals(r['value'], '22')
r = self.do_get('bts.0.trx.0.max-power-reduction')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.max-power-reduction')
self.assertEquals(r['value'], '22')
r = self.do_set('bts.0.trx.0.max-power-reduction', '1')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Value must be even')
def testTrxArfcn(self):
r = self.do_get('bts.0.trx.0.arfcn')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.arfcn')
self.assertEquals(r['value'], '871')
r = self.do_set('bts.0.trx.0.arfcn', '873')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.arfcn')
self.assertEquals(r['value'], '873')
r = self.do_get('bts.0.trx.0.arfcn')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.trx.0.arfcn')
self.assertEquals(r['value'], '873')
r = self.do_set('bts.0.trx.0.arfcn', '2000')
self.assertEquals(r['mtype'], 'ERROR')
self.assertEquals(r['error'], 'Input not within the range')
def testRfLock(self):
r = self.do_get('bts.0.rf_state')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.rf_state')
self.assertEquals(r['value'], 'inoperational,unlocked,on')
r = self.do_set('rf_locked', '1')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'rf_locked')
self.assertEquals(r['value'], '1')
time.sleep(1.5)
r = self.do_get('bts.0.rf_state')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.rf_state')
self.assertEquals(r['value'], 'inoperational,locked,off')
r = self.do_get('rf_locked')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'rf_locked')
self.assertEquals(r['value'], 'state=off,policy=off')
r = self.do_set('rf_locked', '0')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'rf_locked')
self.assertEquals(r['value'], '0')
time.sleep(1.5)
r = self.do_get('bts.0.rf_state')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.rf_state')
self.assertEquals(r['value'], 'inoperational,unlocked,on')
r = self.do_get('rf_locked')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'rf_locked')
self.assertEquals(r['value'], 'state=off,policy=on')
def testTimezone(self):
r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off')
r = self.do_set('timezone', '-2,15,2')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2')
r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2')
# Test invalid input
r = self.do_set('timezone', '-2,15,2,5,6,7')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2')
r = self.do_set('timezone', '-2,15')
self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('timezone', '-2')
self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('timezone', '1')
r = self.do_set('timezone', 'off')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off')
r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off')
def testMcc(self):
r = self.do_set('mcc', '23')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
self.assertEquals(r['value'], '23')
r = self.do_set('mcc', '023')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
self.assertEquals(r['value'], '23')
def testMnc(self):
r = self.do_set('mnc', '9')
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
self.assertEquals(r['value'], '9')
r = self.do_set('mnc', '09')
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
self.assertEquals(r['value'], '9')
def testMccMncApply(self):
# Test some invalid input
r = self.do_set('mcc-mnc-apply', 'WRONG')
self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('mcc-mnc-apply', '1,')
self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('mcc-mnc-apply', '200,3')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'mcc-mnc-apply')
self.assertEquals(r['value'], 'Tried to drop the BTS')
# Set it again
r = self.do_set('mcc-mnc-apply', '200,3')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'mcc-mnc-apply')
self.assertEquals(r['value'], 'Nothing changed')
# Change it
r = self.do_set('mcc-mnc-apply', '200,4')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'mcc-mnc-apply')
self.assertEquals(r['value'], 'Tried to drop the BTS')
# Change it
r = self.do_set('mcc-mnc-apply', '201,4')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'mcc-mnc-apply')
self.assertEquals(r['value'], 'Tried to drop the BTS')
# Verify
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
self.assertEquals(r['value'], '4')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
self.assertEquals(r['value'], '201')
# Change it
r = self.do_set('mcc-mnc-apply', '202,03')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'mcc-mnc-apply')
self.assertEquals(r['value'], 'Tried to drop the BTS')
r = self.do_get('mnc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mnc')
self.assertEquals(r['value'], '3')
r = self.do_get('mcc')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'mcc')
self.assertEquals(r['value'], '202')
class TestCtrlNAT(TestCtrlBase):
def ctrl_command(self):
return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-c",
"doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"]
def ctrl_app(self):
return (4250, "./src/osmo-bsc_nat/osmo-bsc_nat", "OsmoNAT", "nat")
def testAccessList(self):
r = self.do_get('net.0.bsc_cfg.0.access-list-name')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'net')
self.assertEquals(r['value'], None)
r = self.do_set('net.0.bsc_cfg.0.access-list-name', 'bla')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'net')
self.assertEquals(r['value'], 'bla')
r = self.do_get('net.0.bsc_cfg.0.access-list-name')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'net')
self.assertEquals(r['value'], 'bla')
r = self.do_set('net.0.bsc_cfg.0.no-access-list-name', '1')
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'net')
self.assertEquals(r['value'], None)
r = self.do_get('net.0.bsc_cfg.0.access-list-name')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'net')
self.assertEquals(r['value'], None)
def testAccessListManagement(self):
r = self.do_set("net.0.add.allow.access-list.404", "abc")
self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set("net.0.add.allow.access-list.bla", "^234$")
self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'net.0.add.allow.access-list.bla')
self.assertEquals(r['value'], 'IMSI allow added to access list')
# TODO.. find a way to actually see if this rule has been
# added. e.g. by implementing a get for the list.
class TestCtrlSGSN(TestCtrlBase):
def ctrl_command(self):
return ["./src/gprs/osmo-sgsn", "-c",
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
def ctrl_app(self):
return (4251, "./src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn")
def testListSubscribers(self):
# TODO. Add command to mark a subscriber as active
r = self.do_get('subscriber-list-active-v1')
self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'subscriber-list-active-v1')
self.assertEquals(r['value'], None)
def add_bsc_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")):
print("Skipping the BSC test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestCtrlBSC)
suite.addTest(test)
def add_nat_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc_nat/osmo-bsc_nat")):
print("Skipping the NAT test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestCtrlNAT)
suite.addTest(test)
def add_sgsn_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-sgsn")):
print("Skipping the SGSN test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestCtrlSGSN)
suite.addTest(test)
if __name__ == '__main__':
import argparse
import sys
workdir = '.'
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", dest="verbose",
action="store_true", help="verbose mode")
parser.add_argument("-p", "--pythonconfpath", dest="p",
help="searchpath for config")
parser.add_argument("-w", "--workdir", dest="w",
help="Working directory")
args = parser.parse_args()
verbose_level = 1
if args.verbose:
verbose_level = 2
verbose = True
if args.w:
workdir = args.w
if args.p:
confpath = args.p
print "confpath %s, workdir %s" % (confpath, workdir)
os.chdir(workdir)
print "Running tests for specific control commands"
suite = unittest.TestSuite()
add_bsc_test(suite, workdir)
add_nat_test(suite, workdir)
add_sgsn_test(suite, workdir)
res = unittest.TextTestRunner(verbosity=verbose_level).run(suite)
sys.exit(len(res.errors) + len(res.failures))

View File

@@ -20,10 +20,12 @@ AM_LDFLAGS = \
EXTRA_DIST = \
mgcp_test.ok \
mgcp_transcoding_test.ok \
mgcpgw_client_test.ok \
$(NULL)
noinst_PROGRAMS = \
mgcp_test \
mgcpgw_client_test \
$(NULL)
if BUILD_MGCP_TRANSCODING
noinst_PROGRAMS += \
@@ -59,3 +61,16 @@ mgcp_transcoding_test_LDADD = \
$(LIBRARY_GSM) \
-lm \
$(NULL)
mgcpgw_client_test_SOURCES = \
mgcpgw_client_test.c \
$(NULL)
mgcpgw_client_test_LDADD = \
$(top_builddir)/src/libosmo-legacy-mgcp/libosmo-legacy-mgcp.la \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBRARY_DL) \
$(LIBOSMONETIF_LIBS) \
$(LIBRARY_GSM) \
$(NULL)

View File

@@ -489,11 +489,11 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp)
static void test_values(void)
{
/* Check that NONE disables all output */
OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0)
/* Check that LOOPBACK enables all output */
OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
MGCP_CONN_RECV_SEND);
MGCP_CONN_RECV_SEND)
}
@@ -541,8 +541,7 @@ static void test_messages(void)
if (msg)
printf("%s failed '%s'\n", t->name, (char *) msg->data);
} else if (strcmp((char *) msg->data, t->exp_resp) != 0)
printf("%s failed.\nExpected:\n%s\nGot:\n%s\n",
t->name, t->exp_resp, (char *) msg->data);
printf("%s failed '%s'\n", t->name, (char *) msg->data);
msgb_free(msg);
if (dummy_packets)
@@ -1212,7 +1211,7 @@ const struct log_info log_info = {
int main(int argc, char **argv)
{
void *msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
msgb_talloc_ctx_init(NULL, 0);
osmo_init_logging(&log_info);
test_strline();
@@ -1231,9 +1230,6 @@ int main(int argc, char **argv)
test_no_name();
test_osmux_cid();
OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
talloc_free(msgb_ctx);
printf("Done\n");
return EXIT_SUCCESS;
}

Some files were not shown because too many files have changed in this diff Show More