Compare commits

...

78 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
8ce50ba2f7 rf: Delay execution of commands
Delay executing RF commands up to a second. If many commands
arrive within a second then just execute the last command.
2011-02-14 23:41:42 +01:00
Holger Hans Peter Freyther
3f9b6a6539 rf: Verify that the requested mode is entered and drop OML in error
Verify that the BTS is following our orders, if we think there was
an error we will drop the OML connection.
2011-02-14 23:27:18 +01:00
Holger Hans Peter Freyther
b5bb75fbfd rf: Remember the last command requested on the RF CMD interface 2011-02-14 22:34:47 +01:00
Holger Hans Peter Freyther
af5b88fb07 welcome: Fix the str concat here as well. Start to count at 0. 2010-11-26 00:13:02 +01:00
Holger Hans Peter Freyther
0366e67f78 vty: For ipaccess we will dump if the OML connection is present 2010-11-25 16:32:32 +01:00
Holger Hans Peter Freyther
c3f0aeee30 mid-call: Do not lose the first word of the message 2010-11-22 22:27:39 +01:00
Holger Hans Peter Freyther
2413efa47b mid-call: Make the mid-call behavior the default for switching things off
When switching the RF off we will always go through the grace
period, add a direct off mode to switch it off directly. Make
the query return a 'g' if we are in the process of switching
things over.
2010-11-22 19:32:13 +01:00
Holger Hans Peter Freyther
e6fd64d000 mid-call: Implement a timer to go from grace to off.
Start the timer... switch it off when we do the final
tranistion by a command.
2010-11-22 19:15:38 +01:00
Holger Hans Peter Freyther
00d34cd8c6 mid-call: Rename ussd-grace to mid-call 2010-11-22 18:31:35 +01:00
Holger Hans Peter Freyther
58c5e587a5 mid-call: Introduce a timeout to switch from grace to rf off. 2010-11-22 18:25:02 +01:00
Holger Hans Peter Freyther
13b24827d7 bsc_msc_ip: Clean the header, the defines can come from bssap.h 2010-11-03 15:52:11 +01:00
Holger Hans Peter Freyther
ba482438a0 ussd: Catch up with libosmocore and pass the gsm48_hdr
Conflicts:

	openbsc/src/ussd.c
2010-10-18 09:54:33 +02:00
Holger Hans Peter Freyther
4cc21eaa42 ussd: Move the code libosmocore, increase the version number.
Move the code to libosmocore, update the header file and the
version required in the configure.in.

Conflicts:

	openbsc/configure.in
	openbsc/include/openbsc/gsm_04_80.h
	openbsc/src/gsm_04_80.c
2010-10-18 09:54:33 +02:00
Holger Hans Peter Freyther
e9f8a258a8 bssap.c: Fix unaligned memory access by using the read_data16 2010-10-08 20:11:47 +08:00
Holger Hans Peter Freyther
5797ca85c1 bssap.c: The lac is only 16bit.. no need to read two bytes of garbage
Recreate a read_data16, use it to parse the LAC from the Cell Identifier..
we check that the length is at least 3 byte and read from byte 1..
which means reading four bytes is totally wrong.
2010-10-08 20:08:36 +08:00
Holger Hans Peter Freyther
2537b2f836 This is 0.3.99.20 with bring-up hacks, possible crash fixes 2010-10-07 05:56:42 +08:00
Holger Hans Peter Freyther
1168d13e0c msc: Only unregister the fd if the fd value is valid.
This makes sure that someone can call bsc_msc_lost multiple times
even if there is no MSC connection. This makes sense as bsc_msc_lost
is public and be called from client code.
2010-10-07 04:55:42 +08:00
Holger Hans Peter Freyther
588c423f12 msc: Stop the connection timeout when we unregister the bfd
When we dropped the connection... stop the timer as we might
call bsc_unregister_fd twice...
2010-10-07 04:42:03 +08:00
Holger Hans Peter Freyther
088601004c gsm_04_80: Require libosmocore for creating USSD messages
Use the libosmocore to create USSD messages, increase the
minimum version of libosmocore, add header files, remove
the code.

Conflicts:

	openbsc/configure.in
	openbsc/include/openbsc/gsm_04_80.h
	openbsc/src/gsm_04_08.c
	openbsc/src/gsm_04_80.c
2010-10-06 23:36:22 +08:00
Holger Hans Peter Freyther
55982ca9a7 oml: In case we get a NACK, drop the OML connection and hope for the best
Assume that a NACK is a onetime failure and that on the next
attempt it will work better. If that is not the case we might
even send a reboot to the BTS.
2010-10-03 01:48:45 +08:00
Holger Hans Peter Freyther
91a035d2fb oml: Another band aid for reliable BTS init...
Sometimes the operative change for the NSE is getting nacked,
this might be due that we send it before we get the OPSTART ACK
for this object class. Send it from the CELL availability as
a workaround. This init code needs to be changed to make these
dependencies work more reliable.
2010-10-02 04:38:04 +08:00
Holger Hans Peter Freyther
5ed2e3004b ipaccess: Re-Enable the delay between commands...
We still need to keep the delay during startup as the
GPRS code tried to initialize too early.
2010-10-02 02:16:13 +08:00
Holger Hans Peter Freyther
00460d3bc5 bsc_msc_ip: Save the welcome text, add an 'e' to the command. 2010-09-29 20:39:09 +08:00
Holger Hans Peter Freyther
dcb7ad3f2c bsc_msc_ip: Save the bsc-welcome-text message 2010-09-29 20:38:26 +08:00
Holger Hans Peter Freyther
74e7cc4c4a Add missing osmo_bsc_grace.h
This file got lost during a rename.
2010-09-29 18:44:43 +08:00
Holger Hans Peter Freyther
667cba9d28 bsc: Send a USSD command after we have a LU Accept and a new_subscriber 2010-09-26 18:49:03 +08:00
Holger Hans Peter Freyther
6f926f0197 bsc: Add a ussd_welcome_text variable and VTY command
Add a command to set the welcome text for the USSD.
2010-09-26 18:49:02 +08:00
Holger Hans Peter Freyther
c98d67d592 bsc: Mark LUs with a different LAC as needing special care
We want to send a welcome USSD to new subscribers, mark subscribers
with a different LAC than this cell as special and hope someone will
follow up with them.
2010-09-26 18:49:02 +08:00
Holger Hans Peter Freyther
43dbcfe2cf bsc: Rename to osmo_bsc_grace to prepare putting it into master 2010-09-16 00:13:01 +08:00
Holger Hans Peter Freyther
98d949b02f bsc: Rename the RF Ctl interface to match master 2010-09-16 00:01:43 +08:00
Holger Hans Peter Freyther
4f5421a482 bsc_msc: Add minimal code to work with the new SCCP version 2010-08-25 12:22:32 +08:00
Holger Hans Peter Freyther
c8fdf0c4b6 bsc_msc_ip: Set the right log area 2010-08-25 00:55:16 +08:00
Holger Hans Peter Freyther
45473477f6 sccp: Use the libosmo-sccp library and remove the internal copy 2010-08-24 22:38:12 +08:00
Holger Hans Peter Freyther
cd7bed5327 bsc: Remember the MSC connection we use for that connection 2010-08-24 22:26:15 +08:00
Holger Hans Peter Freyther
83594c1f2c oml: Workaround for vty misusage...
Move the OML_NODE below the CONFIG_NODE so that the vty->index
will not be restored when we exit the node. If we do restore the
node we will end up with a double free.
2010-08-11 04:27:25 +08:00
Holger Hans Peter Freyther
7e1524644b mgcp: Speculative mgcp fix...
We really have 32 channels per multiplex... so use the right
number... or at least it seems we do have 32.
2010-08-10 20:24:40 +08:00
Holger Hans Peter Freyther
3ec13ed3a8 OML: Introduce minimal VTY command set to interact with OML managed objects
Conflicts:

	openbsc/include/openbsc/abis_nm.h
	openbsc/src/Makefile.am
	openbsc/src/vty_interface.c
2010-08-10 20:13:38 +08:00
Holger Hans Peter Freyther
11557ecd8c mgcp: Reduce the log level to debug for these calls. 2010-08-08 07:28:54 +08:00
Holger Hans Peter Freyther
c737fbd4af mgcp: Remember if the endpoint was allocated...
Do not use the CI_UNUSED to decide if an endpoint is allocated
but introduce a new flag. This way only the CRCX and free_endp
play with the allocated field.
2010-08-08 07:28:45 +08:00
Holger Hans Peter Freyther
24963554a8 mgcp: Add a callback to inform the client that an endpoint got reallocated 2010-08-08 07:28:36 +08:00
Holger Hans Peter Freyther
c7bd29e6d7 mgcp: Make the CI uint32_t all the way to avoid mismatch
Conflicts:

	openbsc/include/openbsc/mgcp.h
	openbsc/src/nat/bsc_mgcp_utils.c
2010-08-08 07:27:23 +08:00
Holger Hans Peter Freyther
137523ef7c mgcp: Fix discovering the RTCP port with the more strict check.
If we have found the BTS and we receive data on the RTCP port
from the IP of the BTS we will set our RTCP port and forward it
to the network and hope it will be useful.
2010-08-08 07:24:22 +08:00
Holger Hans Peter Freyther
0457b4b6da mgcp: Determine the proto properly... 2010-08-08 07:24:13 +08:00
Holger Hans Peter Freyther
c372b1eb75 bsc_msc: Remove the except code as it is wrong...
Remove wrong code that is luckily not called. We would end up
in a reconnect and attempt to bsc_fd_register the same socket
again. I am removing this part of the code as it is not used
and it would need to know if the fd has ever been registered
or not...
2010-08-08 07:24:06 +08:00
Holger Hans Peter Freyther
55228e31be mgcp: Add instrumentation code to find a possible port leak/bsc-fd corruption 2010-08-08 07:23:58 +08:00
Holger Hans Peter Freyther
db544db73a mgcp: Move the mgcp_free_endp into the right path for the CRCX failure 2010-08-08 07:23:51 +08:00
Holger Hans Peter Freyther
f49d616427 mgcp: Fix a filedescriptor leak in case the bind is failing. 2010-08-08 07:23:44 +08:00
Holger Hans Peter Freyther
1eecb1689b mgcp: Enable the tap after configuring it... 2010-08-08 07:23:36 +08:00
Holger Hans Peter Freyther
f55fc02e87 mgcp: Add a call tap feature to forward audio to another forward port
For debugging it is useful to forward (tee) UDP packets to another
system and use gstreamer to inspect the rtp stream. This is untested
code and might contain bugs.... and of course only tap your own calls.
2010-08-08 07:23:29 +08:00
Holger Hans Peter Freyther
6bb3065e6d mgcp: Patch RTP packets again if that is allowed. 2010-08-08 07:23:22 +08:00
Holger Hans Peter Freyther
3c30a4bb1f mgcp: Get the for network/for bts flag right. 2010-08-08 07:23:15 +08:00
Holger Hans Peter Freyther
636c1cadd8 mgcp: Be more strict on the source addr/source port of the bts
Once we have discovered the bts we will not accept data from
anything else. The call will drop if the BTS is changing the
ip address of the nat anyway.
2010-08-08 07:23:08 +08:00
Holger Hans Peter Freyther
20f3d21665 mgcp: Only discover the bts once, the extra check got lost 2010-08-08 07:22:55 +08:00
Holger Hans Peter Freyther
889fd79511 mgcp: Allow to dynamically allocate ports from a range..
Allow to switch to a dynamic port allocator and not reuse
the ports for a long time... This should help with a crazy
network sending two streams at the same time.
2010-08-08 07:22:40 +08:00
Holger Hans Peter Freyther
7e25253b71 mgcp: Allow to have a different port allocation mode 2010-08-08 07:22:28 +08:00
Holger Hans Peter Freyther
f90c8c9d75 mgcp: Prepare to have different port allocation strategies. 2010-08-08 07:22:06 +08:00
Holger Hans Peter Freyther
08a366f11f mgcp: Fix the signature of the change_cb to not carry the port. 2010-08-08 07:21:58 +08:00
Holger Hans Peter Freyther
c12bfa45a5 mgcp: Separate recv from net/bts and remove autodetection
This allows a more strict check on the source of RTP messages
and we can more easily reject those. For the BTS without an ip
address we will also update the ip address.
2010-08-08 07:21:51 +08:00
Holger Hans Peter Freyther
e320fc115a mgcp: Move the loopback code into the common send as well. 2010-08-08 07:21:43 +08:00
Holger Hans Peter Freyther
5bf8f95701 mgcp: Remove the receive code into a new method. 2010-08-08 07:21:22 +08:00
Holger Hans Peter Freyther
6989b57350 mgcp: Move the selection of the right source port to a new method 2010-08-08 07:19:17 +08:00
Holger Hans Peter Freyther
edd980619c mgcp: Allocate a different port for the networking...
Use the right source port when sending the message.

Conflicts:

	openbsc/include/openbsc/mgcp.h
2010-08-08 07:18:37 +08:00
Holger Hans Peter Freyther
2c362abfb4 mgcp: Rename the base port to bts_base as it will be used for the bts 2010-08-08 07:18:16 +08:00
Holger Hans Peter Freyther
f8e0838f7a mgcp: Move the bfd for rtp/rtcp into the port
Stop using the memset in the mgcp_rtp_end_reset as we
will reset the list pointers and then have a mess..
2010-08-08 07:18:08 +08:00
Holger Hans Peter Freyther
ec2886d1bd mgcp: Make the function internal, only used by the init/config code 2010-08-08 07:18:00 +08:00
Holger Hans Peter Freyther
865ba8b572 mgcp: Rename the bind method to show it is only binding for the bts port 2010-08-08 07:17:52 +08:00
Holger Hans Peter Freyther
9be1b5495f mgcp: Only use early bind for the BTS socket.
Simplify the code by onlt allowing one way to allocate
a socket.
2010-08-08 07:17:42 +08:00
Holger Hans Peter Freyther
7cf7d27d10 mgcp: Attempt to separate the RTP/RTCP port for the Network and for the BTS
We plan to have two different ports for the network and for the
BTS to avoid detecting the BTS and to dynamically allocate the
port to have old data not go to a new socket.

Conflicts:

	openbsc/src/nat/bsc_mgcp_utils.c
2010-08-08 07:17:22 +08:00
Holger Hans Peter Freyther
9002169dcd mgcp: Group the state for bts/net into a struct and have two instances
Group the data that each end (network/bts) have into a struct and use
this struct throughout the sourcecode.

Conflicts:

	openbsc/src/nat/bsc_mgcp_utils.c
2010-08-08 07:16:55 +08:00
Holger Hans Peter Freyther
43242f8947 mgcp: Remove the forwarding mode as it was not used.
Conflicts:

	openbsc/include/openbsc/mgcp.h
2010-08-08 07:16:31 +08:00
Holger Hans Peter Freyther
83961de565 mgcp: Fix the payload_type... it broke in 7cdc62c012 2010-08-08 07:14:58 +08:00
Holger Hans Peter Freyther
19776f70a2 mgcp: Fix the reversed net/bts... which has not cause any issue.. 2010-08-08 07:14:46 +08:00
Holger Hans Peter Freyther
6233ab9859 mgcp: Pass the whole endpoint to the patch method. 2010-08-08 07:14:37 +08:00
Holger Hans Peter Freyther
0037badb02 mgcp: Fix the order of the arguments... 2010-08-08 07:14:07 +08:00
Holger Hans Peter Freyther
054efe1ef2 mgcp: Print the conn mode as well 2010-08-08 07:13:58 +08:00
Holger Hans Peter Freyther
68fc12d89b mgcp: Disable the actual patching... this is a temporary hack 2010-08-08 07:13:50 +08:00
Holger Hans Peter Freyther
7eccf5b0a5 mgcp: Print the system for the duplicate SSRC... 2010-08-08 07:13:40 +08:00
Holger Hans Peter Freyther
6d346d8931 bsc_msc: Fix the naming of this function. 2010-08-08 07:13:20 +08:00
43 changed files with 1167 additions and 3971 deletions

View File

@@ -4,7 +4,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = include src tests
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = openbsc.pc libsccp.pc
pkgconfig_DATA = openbsc.pc
BUILT_SOURCES = $(top_srcdir)/.version
$(top_srcdir)/.version:

View File

@@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT(openbsc, 0.3.99.19onwaves)
AC_INIT(openbsc, 0.3.99.20onwaves)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
dnl kernel style compile messages
@@ -15,7 +15,8 @@ dnl checks for libraries
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.15)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.23)
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.3)
dnl checks for header files
AC_HEADER_STDC
@@ -39,10 +40,8 @@ AM_CONFIG_HEADER(bscconfig.h)
AC_OUTPUT(
openbsc.pc
libsccp.pc
include/openbsc/Makefile
include/vty/Makefile
include/sccp/Makefile
include/Makefile
src/Makefile
tests/Makefile
@@ -50,5 +49,4 @@ AC_OUTPUT(
tests/gsm0408/Makefile
tests/db/Makefile
tests/channel/Makefile
tests/sccp/Makefile
Makefile)

View File

@@ -1,3 +1,3 @@
SUBDIRS = openbsc vty sccp
SUBDIRS = openbsc vty
noinst_HEADERS = mISDNif.h compat_af_isdn.h

View File

@@ -6,8 +6,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h rest_octets.h \
system_information.h handover.h mgcp_internal.h \
vty.h bssap.h bsc_msc.h bsc_nat.h bsc_msc_rf.h \
bsc_msc_grace.h
vty.h bssap.h bsc_msc.h bsc_nat.h osmo_bsc_rf.h \
osmo_bsc_grace.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -55,6 +55,8 @@ struct ipac_bcch_info {
u_int8_t ca_list_si1[16];
};
extern const struct value_string abis_nm_adm_state_names[];
extern const struct value_string abis_nm_obj_class_names[];
extern const struct tlv_definition nm_att_tlvdef;
/* PUBLIC */
@@ -172,4 +174,7 @@ const char *nm_avail_name(u_int8_t avail);
int nm_is_running(struct gsm_nm_state *s);
void abis_nm_clear_queue(struct gsm_bts *bts);
int abis_nm_vty_init(void);
#endif /* _NM_H */

View File

@@ -1,22 +0,0 @@
#ifndef BSC_MSC_RF
#define BSC_MSC_RF
#include <osmocore/write_queue.h>
struct gsm_network;
struct bsc_msc_rf {
/* the value of signal.h */
int policy;
struct bsc_fd listen;
struct gsm_network *gsm_network;
};
struct bsc_msc_rf_conn {
struct write_queue queue;
struct bsc_msc_rf *rf;
};
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net);
#endif

View File

@@ -25,7 +25,7 @@
#include "mgcp.h"
#include <sys/types.h>
#include <sccp/sccp_types.h>
#include <osmocom/sccp/sccp_types.h>
#include <osmocore/select.h>
#include <osmocore/msgb.h>
@@ -322,7 +322,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
int bsc_mgcp_extract_ci(const char *resp);
uint32_t bsc_mgcp_extract_ci(const char *resp);
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);

View File

@@ -6,302 +6,9 @@
#include <stdlib.h>
#include <osmocore/msgb.h>
#include <osmocore/protocol/gsm_08_08.h>
#include <openbsc/gsm_data.h>
/*
* this is from GSM 03.03 CGI but is copied in GSM 08.08
* in § 3.2.2.27 for Cell Identifier List
*/
enum CELL_IDENT {
CELL_IDENT_WHOLE_GLOBAL = 0,
CELL_IDENT_LAC_AND_CI = 1,
CELL_IDENT_CI = 2,
CELL_IDENT_NO_CELL = 3,
CELL_IDENT_LAI_AND_LAC = 4,
CELL_IDENT_LAC = 5,
CELL_IDENT_BSS = 6,
CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8,
CELL_IDENT_UTRAN_RNC = 9,
CELL_IDENT_UTRAN_LAC_RNC = 10,
};
/* GSM 08.06 § 6.3 */
enum BSSAP_MSG_TYPE {
BSSAP_MSG_BSS_MANAGEMENT = 0x0,
BSSAP_MSG_DTAP = 0x1,
};
struct bssmap_header {
u_int8_t type;
u_int8_t length;
} __attribute__((packed));
struct dtap_header {
u_int8_t type;
u_int8_t link_id;
u_int8_t length;
} __attribute__((packed));
enum BSS_MAP_MSG_TYPE {
BSS_MAP_MSG_RESERVED_0 = 0,
/* ASSIGNMENT MESSAGES */
BSS_MAP_MSG_ASSIGMENT_RQST = 1,
BSS_MAP_MSG_ASSIGMENT_COMPLETE = 2,
BSS_MAP_MSG_ASSIGMENT_FAILURE = 3,
/* HANDOVER MESSAGES */
BSS_MAP_MSG_HANDOVER_RQST = 16,
BSS_MAP_MSG_HANDOVER_REQUIRED = 17,
BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
BSS_MAP_MSG_HANDOVER_CMD = 19,
BSS_MAP_MSG_HANDOVER_COMPLETE = 20,
BSS_MAP_MSG_HANDOVER_SUCCEEDED = 21,
BSS_MAP_MSG_HANDOVER_FAILURE = 22,
BSS_MAP_MSG_HANDOVER_PERFORMED = 23,
BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE = 24,
BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE = 25,
BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT = 26,
BSS_MAP_MSG_HANDOVER_DETECT = 27,
/* RELEASE MESSAGES */
BSS_MAP_MSG_CLEAR_CMD = 32,
BSS_MAP_MSG_CLEAR_COMPLETE = 33,
BSS_MAP_MSG_CLEAR_RQST = 34,
BSS_MAP_MSG_RESERVED_1 = 35,
BSS_MAP_MSG_RESERVED_2 = 36,
BSS_MAP_MSG_SAPI_N_REJECT = 37,
BSS_MAP_MSG_CONFUSION = 38,
/* OTHER CONNECTION RELATED MESSAGES */
BSS_MAP_MSG_SUSPEND = 40,
BSS_MAP_MSG_RESUME = 41,
BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
BSS_MAP_MSG_PERFORM_LOCATION_RQST = 43,
BSS_MAP_MSG_LSA_INFORMATION = 44,
BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE = 45,
BSS_MAP_MSG_PERFORM_LOCATION_ABORT = 46,
BSS_MAP_MSG_COMMON_ID = 47,
/* GENERAL MESSAGES */
BSS_MAP_MSG_RESET = 48,
BSS_MAP_MSG_RESET_ACKNOWLEDGE = 49,
BSS_MAP_MSG_OVERLOAD = 50,
BSS_MAP_MSG_RESERVED_3 = 51,
BSS_MAP_MSG_RESET_CIRCUIT = 52,
BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE = 53,
BSS_MAP_MSG_MSC_INVOKE_TRACE = 54,
BSS_MAP_MSG_BSS_INVOKE_TRACE = 55,
BSS_MAP_MSG_CONNECTIONLESS_INFORMATION = 58,
/* TERRESTRIAL RESOURCE MESSAGES */
BSS_MAP_MSG_BLOCK = 64,
BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE = 65,
BSS_MAP_MSG_UNBLOCK = 66,
BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE = 67,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK = 68,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE = 69,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK = 70,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
BSS_MAP_MSG_UNEQUIPPED_CIRCUIT = 72,
BSS_MAP_MSG_CHANGE_CIRCUIT = 78,
BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE = 79,
/* RADIO RESOURCE MESSAGES */
BSS_MAP_MSG_RESOURCE_RQST = 80,
BSS_MAP_MSG_RESOURCE_INDICATION = 81,
BSS_MAP_MSG_PAGING = 82,
BSS_MAP_MSG_CIPHER_MODE_CMD = 83,
BSS_MAP_MSG_CLASSMARK_UPDATE = 84,
BSS_MAP_MSG_CIPHER_MODE_COMPLETE = 85,
BSS_MAP_MSG_QUEUING_INDICATION = 86,
BSS_MAP_MSG_COMPLETE_LAYER_3 = 87,
BSS_MAP_MSG_CLASSMARK_RQST = 88,
BSS_MAP_MSG_CIPHER_MODE_REJECT = 89,
BSS_MAP_MSG_LOAD_INDICATION = 90,
/* VGCS/VBS */
BSS_MAP_MSG_VGCS_VBS_SETUP = 4,
BSS_MAP_MSG_VGCS_VBS_SETUP_ACK = 5,
BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE = 6,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST = 7,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT = 28,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE = 29,
BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30,
BSS_MAP_MSG_UPLINK_RQST = 31,
BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39,
BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73,
BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74,
BSS_MAP_MSG_UPLINK_REJECT_CMD = 75,
BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76,
BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77,
};
enum GSM0808_IE_CODING {
GSM0808_IE_CIRCUIT_IDENTITY_CODE = 1,
GSM0808_IE_RESERVED_0 = 2,
GSM0808_IE_RESOURCE_AVAILABLE = 3,
GSM0808_IE_CAUSE = 4,
GSM0808_IE_CELL_IDENTIFIER = 5,
GSM0808_IE_PRIORITY = 6,
GSM0808_IE_LAYER_3_HEADER_INFORMATION = 7,
GSM0808_IE_IMSI = 8,
GSM0808_IE_TMSI = 9,
GSM0808_IE_ENCRYPTION_INFORMATION = 10,
GSM0808_IE_CHANNEL_TYPE = 11,
GSM0808_IE_PERIODICITY = 12,
GSM0808_IE_EXTENDED_RESOURCE_INDICATOR = 13,
GSM0808_IE_NUMBER_OF_MSS = 14,
GSM0808_IE_RESERVED_1 = 15,
GSM0808_IE_RESERVED_2 = 16,
GSM0808_IE_RESERVED_3 = 17,
GSM0808_IE_CLASSMARK_INFORMATION_T2 = 18,
GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19,
GSM0808_IE_INTERFERENCE_BAND_TO_USE = 20,
GSM0808_IE_RR_CAUSE = 21,
GSM0808_IE_RESERVED_4 = 22,
GSM0808_IE_LAYER_3_INFORMATION = 23,
GSM0808_IE_DLCI = 24,
GSM0808_IE_DOWNLINK_DTX_FLAG = 25,
GSM0808_IE_CELL_IDENTIFIER_LIST = 26,
GSM0808_IE_RESPONSE_RQST = 27,
GSM0808_IE_RESOURCE_INDICATION_METHOD = 28,
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1 = 29,
GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST = 30,
GSM0808_IE_DIAGNOSTIC = 31,
GSM0808_IE_LAYER_3_MESSAGE_CONTENTS = 32,
GSM0808_IE_CHOSEN_CHANNEL = 33,
GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE = 34,
GSM0808_IE_CIPHER_RESPONSE_MODE = 35,
GSM0808_IE_CHANNEL_NEEDED = 36,
GSM0808_IE_TRACE_TYPE = 37,
GSM0808_IE_TRIGGERID = 38,
GSM0808_IE_TRACE_REFERENCE = 39,
GSM0808_IE_TRANSACTIONID = 40,
GSM0808_IE_MOBILE_IDENTITY = 41,
GSM0808_IE_OMCID = 42,
GSM0808_IE_FORWARD_INDICATOR = 43,
GSM0808_IE_CHOSEN_ENCR_ALG = 44,
GSM0808_IE_CIRCUIT_POOL = 45,
GSM0808_IE_CIRCUIT_POOL_LIST = 46,
GSM0808_IE_TIME_INDICATION = 47,
GSM0808_IE_RESOURCE_SITUATION = 48,
GSM0808_IE_CURRENT_CHANNEL_TYPE_1 = 49,
GSM0808_IE_QUEUEING_INDICATOR = 50,
GSM0808_IE_SPEECH_VERSION = 64,
GSM0808_IE_ASSIGNMENT_REQUIREMENT = 51,
GSM0808_IE_TALKER_FLAG = 53,
GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54,
GSM0808_IE_GROUP_CALL_REFERENCE = 55,
GSM0808_IE_EMLPP_PRIORITY = 56,
GSM0808_IE_CONFIG_EVO_INDI = 57,
GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58,
GSM0808_IE_LSA_IDENTIFIER = 59,
GSM0808_IE_LSA_IDENTIFIER_LIST = 60,
GSM0808_IE_LSA_INFORMATION = 61,
GSM0808_IE_LCS_QOS = 62,
GSM0808_IE_LSA_ACCESS_CTRL_SUPPR = 63,
GSM0808_IE_LCS_PRIORITY = 67,
GSM0808_IE_LOCATION_TYPE = 68,
GSM0808_IE_LOCATION_ESTIMATE = 69,
GSM0808_IE_POSITIONING_DATA = 70,
GSM0808_IE_LCS_CAUSE = 71,
GSM0808_IE_LCS_CLIENT_TYPE = 72,
GSM0808_IE_APDU = 73,
GSM0808_IE_NETWORK_ELEMENT_IDENTITY = 74,
GSM0808_IE_GPS_ASSISTANCE_DATA = 75,
GSM0808_IE_DECIPHERING_KEYS = 76,
GSM0808_IE_RETURN_ERROR_RQST = 77,
GSM0808_IE_RETURN_ERROR_CAUSE = 78,
GSM0808_IE_SEGMENTATION = 79,
GSM0808_IE_SERVICE_HANDOVER = 80,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
GSM0808_IE_RESERVED_5 = 65,
GSM0808_IE_RESERVED_6 = 66,
};
enum gsm0808_cause {
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE = 0,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE = 1,
GSM0808_CAUSE_UPLINK_QUALITY = 2,
GSM0808_CAUSE_UPLINK_STRENGTH = 3,
GSM0808_CAUSE_DOWNLINK_QUALITY = 4,
GSM0808_CAUSE_DOWNLINK_STRENGTH = 5,
GSM0808_CAUSE_DISTANCE = 6,
GSM0808_CAUSE_O_AND_M_INTERVENTION = 7,
GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION = 8,
GSM0808_CAUSE_CALL_CONTROL = 9,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION = 10,
GSM0808_CAUSE_HANDOVER_SUCCESSFUL = 11,
GSM0808_CAUSE_BETTER_CELL = 12,
GSM0808_CAUSE_DIRECTED_RETRY = 13,
GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL = 14,
GSM0808_CAUSE_TRAFFIC = 15,
GSM0808_CAUSE_EQUIPMENT_FAILURE = 32,
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE = 33,
GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE = 34,
GSM0808_CAUSE_CCCH_OVERLOAD = 35,
GSM0808_CAUSE_PROCESSOR_OVERLOAD = 36,
GSM0808_CAUSE_BSS_NOT_EQUIPPED = 37,
GSM0808_CAUSE_MS_NOT_EQUIPPED = 38,
GSM0808_CAUSE_INVALID_CELL = 39,
GSM0808_CAUSE_TRAFFIC_LOAD = 40,
GSM0808_CAUSE_PREEMPTION = 41,
GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE = 48,
GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH = 49,
GSM0808_CAUSE_SWITCH_CIRCUIT_POOL = 50,
GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE = 51,
GSM0808_CAUSE_LSA_NOT_ALLOWED = 52,
GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED = 64,
GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED = 80,
GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS = 81,
GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING = 82,
GSM0808_CAUSE_INCORRECT_VALUE = 83,
GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE = 84,
GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT = 85,
GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC = 96,
};
/* GSM 08.08 3.2.2.11 Channel Type */
enum gsm0808_chan_indicator {
GSM0808_CHAN_SPEECH = 1,
GSM0808_CHAN_DATA = 2,
GSM0808_CHAN_SIGN = 3,
};
enum gsm0808_chan_rate_type_data {
GSM0808_DATA_FULL_BM = 0x8,
GSM0808_DATA_HALF_LM = 0x9,
GSM0808_DATA_FULL_RPREF = 0xa,
GSM0808_DATA_HALF_PREF = 0xb,
GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_DATA_MULTI_MASK = 0x20,
GSM0808_DATA_MULTI_MASK_NO_CHANGE = 0x30,
};
enum gsm0808_chan_rate_type_speech {
GSM0808_SPEECH_FULL_BM = 0x8,
GSM0808_SPEECH_HALF_LM = 0x9,
GSM0808_SPEECH_FULL_PREF= 0xa,
GSM0808_SPEECH_HALF_PREF= 0xb,
GSM0808_SPEECH_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_SPEECH_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_SPEECH_PERM = 0xf,
GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
};
enum gsm0808_permitted_speech {
GSM0808_PERM_FR1 = 0x01,
GSM0808_PERM_FR2 = 0x11,
GSM0808_PERM_FR3 = 0x21,
GSM0808_PERM_HR1 = GSM0808_PERM_FR1 | 0x4,
GSM0808_PERM_HR2 = GSM0808_PERM_FR2 | 0x4,
GSM0808_PERM_HR3 = GSM0808_PERM_FR3 | 0x4,
};
int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned int length);
int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length);

View File

@@ -3,28 +3,13 @@
#include <osmocore/msgb.h>
#include <osmocore/protocol/gsm_04_80.h>
#include <osmocore/gsm0480.h>
#define MAX_LEN_USSD_STRING 31
struct ussd_request {
char text[MAX_LEN_USSD_STRING + 1];
u_int8_t transaction_id;
u_int8_t invoke_id;
};
int gsm0480_decode_ussd_request(const struct msgb *msg,
struct ussd_request *request);
int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_text,
const struct ussd_request *req);
int gsm0480_send_ussd_reject(const struct msgb *msg,
const struct ussd_request *request);
struct msgb *gsm0480_create_notifySS(const char *text);
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertLevel, const char *text);
int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id);
int gsm0480_wrap_facility(struct msgb *msg);
int gsm0480_send_ussdNotify(struct gsm_lchan *lchan, int level, const char *text);
int gsm0480_send_releaseComplete(struct gsm_lchan *lchan);

View File

@@ -88,7 +88,7 @@ typedef int gsm_cbfn(unsigned int hooknum,
struct msgb *msg,
void *data, void *param);
struct bsc_msc_rf;
struct osmo_bsc_rf;
struct sccp_connection;
/* Real authentication information containing Ki */
@@ -125,6 +125,8 @@ struct bss_sccp_connection_data {
struct sccp_connection *sccp;
int ciphering_handled : 1;
int new_subscriber;
/* Timers... */
/* for assginment command */
@@ -145,6 +147,9 @@ struct bss_sccp_connection_data {
struct llist_head sccp_queue;
unsigned int sccp_queue_size;
/* which msc connection to use? */
struct bsc_msc_connection *msc_con;
/* Active connections */
struct llist_head active_connections;
};
@@ -697,8 +702,10 @@ struct gsm_network {
struct bsc_msc_connection *msc_con;
int ping_timeout;
int pong_timeout;
struct bsc_msc_rf *rf;
char *ussd_grace_txt;
struct osmo_bsc_rf *rf;
char *mid_call_txt;
int mid_call_timeout;
char *ussd_welcome_txt;
};
#define SMS_HDR_SIZE 128

View File

@@ -29,6 +29,7 @@
#include <arpa/inet.h>
#define RTP_PORT_DEFAULT 4000
#define RTP_PORT_NET_DEFAULT 16000
/**
* Calculate the RTP audio port for the given multiplex
* and the direction. This allows a semi static endpoint
@@ -74,10 +75,29 @@ struct mgcp_config;
#define MGCP_POLICY_REJECT 5
#define MGCP_POLICY_DEFER 6
typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp);
typedef int (*mgcp_realloc)(struct mgcp_config *cfg, int endpoint);
typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state);
typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id);
typedef int (*mgcp_reset)(struct mgcp_config *cfg);
#define PORT_ALLOC_STATIC 0
#define PORT_ALLOC_DYNAMIC 1
/**
* This holds information on how to allocate ports
*/
struct mgcp_port_range {
int mode;
/* pre-allocated from a base? */
int base_port;
/* dynamically allocated */
int range_start;
int range_end;
int last_port;
};
struct mgcp_config {
/* common configuration */
int source_port;
@@ -91,16 +111,11 @@ struct mgcp_config {
char *audio_name;
int audio_payload;
int audio_loop;
int early_bind;
int rtp_base_port;
struct mgcp_port_range bts_ports;
struct mgcp_port_range net_ports;
int endp_dscp;
/* only used in forward mode */
char *forward_ip;
int forward_port;
unsigned int last_call_id;
/* endpoint configuration */
unsigned int number_endpoints;
struct mgcp_endpoint *endpoints;
@@ -112,7 +127,10 @@ struct mgcp_config {
mgcp_change change_cb;
mgcp_policy policy_cb;
mgcp_reset reset_cb;
mgcp_realloc realloc_cb;
void *data;
uint32_t last_call_id;
};
/* config management */
@@ -120,7 +138,6 @@ struct mgcp_config *mgcp_config_alloc(void);
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg);
int mgcp_vty_init(void);
int mgcp_endpoints_allocate(struct mgcp_config *cfg);
int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
void mgcp_free_endp(struct mgcp_endpoint *endp);
/*
@@ -134,7 +151,7 @@ static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
{
if (timeslot == 0)
timeslot = 1;
return timeslot + (31 * multiplex);
return timeslot + (32 * multiplex);
}

View File

@@ -49,44 +49,65 @@ struct mgcp_rtp_state {
int32_t timestamp_offset;
};
struct mgcp_rtp_end {
/* statistics */
unsigned int packets;
struct in_addr addr;
/* in network byte order */
int rtp_port, rtcp_port;
int payload_type;
/*
* Each end has a socket...
*/
struct bsc_fd rtp;
struct bsc_fd rtcp;
int local_port;
int local_alloc;
};
enum {
MGCP_TAP_BTS_IN,
MGCP_TAP_BTS_OUT,
MGCP_TAP_NET_IN,
MGCP_TAP_NET_OUT,
/* last element */
MGCP_TAP_COUNT
};
struct mgcp_rtp_tap {
int enabled;
struct sockaddr_in forward;
};
struct mgcp_endpoint {
int ci;
int allocated;
uint32_t ci;
char *callid;
char *local_options;
int conn_mode;
int orig_mode;
int bts_payload_type;
int net_payload_type;
/* the local rtp port we are binding to */
int rtp_port;
/*
* RTP mangling:
* - we get RTP and RTCP to us and need to forward to the BTS
* - we get RTP and RTCP from the BTS and forward to the network
*/
struct bsc_fd local_rtp;
struct bsc_fd local_rtcp;
struct in_addr remote;
struct in_addr bts;
/* in network byte order */
int net_rtp, net_rtcp;
int bts_rtp, bts_rtcp;
/* backpointer */
struct mgcp_config *cfg;
/* statistics */
unsigned int in_bts;
unsigned int in_remote;
/* port status for bts/net */
struct mgcp_rtp_end bts_end;
struct mgcp_rtp_end net_end;
/* sequence bits */
struct mgcp_rtp_state net_state;
struct mgcp_rtp_state bts_state;
/* SSRC/seq/ts patching for loop */
int allow_patch;
/* tap for the endpoint */
struct mgcp_rtp_tap taps[MGCP_TAP_COUNT];
};
#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
@@ -100,5 +121,8 @@ int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
struct mgcp_msg_ptr *ptr, int size,
const char **transaction_id, struct mgcp_endpoint **endp);
int mgcp_send_dummy(struct mgcp_endpoint *endp);
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_free_rtp_port(struct mgcp_rtp_end *end);
#endif

View File

@@ -19,8 +19,8 @@
*
*/
#ifndef BSC_MSC_GRACE_H
#define BSC_MSC_GRACE_H
#ifndef OSMO_BSC_GRACE_H
#define OSMO_BSC_GRACE_H
#include "gsm_data.h"

View File

@@ -0,0 +1,35 @@
#ifndef BSC_MSC_RF
#define BSC_MSC_RF
#include <osmocore/write_queue.h>
#include <osmocore/timer.h>
struct gsm_network;
struct osmo_bsc_rf {
/* the value of signal.h */
int policy;
struct bsc_fd listen;
struct gsm_network *gsm_network;
const char *last_state_command;
/* delay the command */
char last_request;
struct timer_list delay_cmd;
/* verify that RF is up as it should be */
struct timer_list rf_check;
/* some handling for the automatic grace switch */
struct timer_list grace_timeout;
};
struct osmo_bsc_rf_conn {
struct write_queue queue;
struct osmo_bsc_rf *rf;
};
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);
#endif

View File

@@ -1,2 +0,0 @@
sccp_HEADERS = sccp_types.h sccp.h
sccpdir = $(includedir)/sccp

View File

@@ -1,177 +0,0 @@
/*
* SCCP management code
*
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef SCCP_H
#define SCCP_H
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "sccp_types.h"
struct msgb;
struct sccp_system;
enum {
SCCP_CONNECTION_STATE_NONE,
SCCP_CONNECTION_STATE_REQUEST,
SCCP_CONNECTION_STATE_CONFIRM,
SCCP_CONNECTION_STATE_ESTABLISHED,
SCCP_CONNECTION_STATE_RELEASE,
SCCP_CONNECTION_STATE_RELEASE_COMPLETE,
SCCP_CONNECTION_STATE_REFUSED,
SCCP_CONNECTION_STATE_SETUP_ERROR,
};
struct sockaddr_sccp {
sa_family_t sccp_family; /* AF_SCCP in the future??? */
u_int8_t sccp_ssn; /* subssystem number for routing */
/* TODO fill in address indicator... if that is ever needed */
/* not sure about these */
/* u_int8_t sccp_class; */
};
/*
* parsed structure of an address
*/
struct sccp_address {
struct sccp_called_party_address address;
u_int8_t ssn;
u_int8_t poi[2];
};
struct sccp_optional_data {
u_int8_t data_len;
u_int8_t data_start;
};
struct sccp_connection {
/* public */
void *data_ctx;
void (*data_cb)(struct sccp_connection *conn, struct msgb *msg, unsigned int len);
void *state_ctx;
void (*state_cb)(struct sccp_connection *, int old_state);
struct sccp_source_reference source_local_reference;
struct sccp_source_reference destination_local_reference;
int connection_state;
/* private */
/* list of active connections */
struct llist_head list;
struct sccp_system *system;
int incoming;
};
/**
* system functionality to implement on top of any other transport layer:
* call sccp_system_incoming for incoming data (from the network)
* sccp will call outgoing whenever outgoing data exists
*/
int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *context);
int sccp_system_incoming(struct msgb *data);
/**
* Send data on an existing connection
*/
int sccp_connection_write(struct sccp_connection *connection, struct msgb *data);
int sccp_connection_send_it(struct sccp_connection *connection);
int sccp_connection_close(struct sccp_connection *connection, int cause);
int sccp_connection_free(struct sccp_connection *connection);
/**
* internal..
*/
int sccp_connection_force_free(struct sccp_connection *conn);
/**
* Create a new socket. Set your callbacks and then call bind to open
* the connection.
*/
struct sccp_connection *sccp_connection_socket(void);
/**
* Open the connection and send additional data
*/
int sccp_connection_connect(struct sccp_connection *conn,
const struct sockaddr_sccp *sccp_called,
struct msgb *data);
/**
* mostly for testing purposes only. Set the accept callback.
* TODO: add true routing information... in analogy to socket, bind, accept
*/
int sccp_connection_set_incoming(const struct sockaddr_sccp *sock,
int (*accept_cb)(struct sccp_connection *connection, void *data),
void *user_data);
/**
* Send data in terms of unit data. A fixed address indicator will be used.
*/
int sccp_write(struct msgb *data,
const struct sockaddr_sccp *sock_sender,
const struct sockaddr_sccp *sock_target, int class);
int sccp_set_read(const struct sockaddr_sccp *sock,
int (*read_cb)(struct msgb *msgb, unsigned int, void *user_data),
void *user_data);
/* generic sock addresses */
extern const struct sockaddr_sccp sccp_ssn_bssap;
/* helpers */
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length);
struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref);
struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref, int cause);
struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *data, uint8_t len);
/**
* Below this are helper functions and structs for parsing SCCP messages
*/
struct sccp_parse_result {
struct sccp_address called;
struct sccp_address calling;
/* point to the msg packet */
struct sccp_source_reference *source_local_reference;
struct sccp_source_reference *destination_local_reference;
/* data pointer */
int data_len;
};
/*
* helper functions for the nat code
*/
int sccp_determine_msg_type(struct msgb *msg);
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result);
#endif

View File

@@ -1,420 +0,0 @@
/*
* ITU Q.713 defined types for SCCP
*
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef SCCP_TYPES_H
#define SCCP_TYPES_H
#include <endian.h>
/* Table 1/Q.713 - SCCP message types */
enum sccp_message_types {
SCCP_MSG_TYPE_CR = 1,
SCCP_MSG_TYPE_CC = 2,
SCCP_MSG_TYPE_CREF = 3,
SCCP_MSG_TYPE_RLSD = 4,
SCCP_MSG_TYPE_RLC = 5,
SCCP_MSG_TYPE_DT1 = 6,
SCCP_MSG_TYPE_DT2 = 7,
SCCP_MSG_TYPE_AK = 8,
SCCP_MSG_TYPE_UDT = 9,
SCCP_MSG_TYPE_UDTS = 10,
SCCP_MSG_TYPE_ED = 11,
SCCP_MSG_TYPE_EA = 12,
SCCP_MSG_TYPE_RSR = 13,
SCCP_MSG_TYPE_RSC = 14,
SCCP_MSG_TYPE_ERR = 15,
SCCP_MSG_TYPE_IT = 16,
SCCP_MSG_TYPE_XUDT = 17,
SCCP_MSG_TYPE_XUDTS = 18,
SCCP_MSG_TYPE_LUDT = 19,
SCCP_MSG_TYPE_LUDTS = 20
};
/* Table 2/Q.713 - SCCP parameter name codes */
enum sccp_parameter_name_codes {
SCCP_PNC_END_OF_OPTIONAL = 0,
SCCP_PNC_DESTINATION_LOCAL_REFERENCE = 1,
SCCP_PNC_SOURCE_LOCAL_REFERENCE = 2,
SCCP_PNC_CALLED_PARTY_ADDRESS = 3,
SCCP_PNC_CALLING_PARTY_ADDRESS = 4,
SCCP_PNC_PROTOCOL_CLASS = 5,
SCCP_PNC_SEGMENTING = 6,
SCCP_PNC_RECEIVE_SEQ_NUMBER = 7,
SCCP_PNC_SEQUENCING = 8,
SCCP_PNC_CREDIT = 9,
SCCP_PNC_RELEASE_CAUSE = 10,
SCCP_PNC_RETURN_CAUSE = 11,
SCCP_PNC_RESET_CAUSE = 12,
SCCP_PNC_ERROR_CAUSE = 13,
SCCP_PNC_REFUSAL_CAUSE = 14,
SCCP_PNC_DATA = 15,
SCCP_PNC_SEGMENTATION = 16,
SCCP_PNC_HOP_COUNTER = 17,
SCCP_PNC_IMPORTANCE = 18,
SCCP_PNC_LONG_DATA = 19,
};
/* Figure 3/Q.713 Called/calling party address */
enum {
SCCP_TITLE_IND_NONE = 0,
SCCP_TITLE_IND_NATURE_ONLY = 1,
SCCP_TITLE_IND_TRANSLATION_ONLY = 2,
SCCP_TITLE_IND_TRANS_NUM_ENC = 3,
SCCP_TITLE_IND_TRANS_NUM_ENC_NATURE = 4,
};
enum {
SCCP_CALL_ROUTE_ON_SSN = 1,
SCCP_CALL_ROUTE_ON_GT = 0,
};
struct sccp_called_party_address {
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t point_code_indicator : 1,
ssn_indicator : 1,
global_title_indicator : 4,
routing_indicator : 1,
reserved : 1;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_int8_t reserved : 1,
routing_indicator : 1,
global_title_indicator : 4,
ssn_indicator : 1,
point_code_indicator : 1;
#endif
u_int8_t data[0];
} __attribute__((packed));
/* indicator indicates presence in the above order */
/* Figure 6/Q.713 */
struct sccp_signalling_point_code {
u_int8_t lsb;
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t msb : 6,
reserved : 2;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_int8_t reserved : 2,
msb : 6;
#endif
} __attribute__((packed));
/* SSN == subsystem number */
enum sccp_subsystem_number {
SCCP_SSN_NOT_KNOWN_OR_USED = 0,
SCCP_SSN_MANAGEMENT = 1,
SCCP_SSN_RESERVED_ITU = 2,
SCCP_SSN_ISDN_USER_PART = 3,
SCCP_SSN_OMAP = 4, /* operation, maint and administration part */
SCCP_SSN_MAP = 5, /* mobile application part */
SCCP_SSN_HLR = 6,
SCCP_SSN_VLR = 7,
SCCP_SSN_MSC = 8,
SCCP_SSN_EIC = 9, /* equipent identifier centre */
SCCP_SSN_AUC = 10, /* authentication centre */
SCCP_SSN_ISDN_SUPPL_SERVICES = 11,
SCCP_SSN_RESERVED_INTL = 12,
SCCP_SSN_ISDN_EDGE_TO_EDGE = 13,
SCCP_SSN_TC_TEST_RESPONDER = 14,
/* From GSM 03.03 8.2 */
SCCP_SSN_BSSAP = 254,
SCCP_SSN_BSSOM = 253,
};
/* Q.713, 3.4.2.3 */
enum {
SCCP_NAI_UNKNOWN = 0,
SCCP_NAI_SUBSCRIBER_NUMBER = 1,
SCCP_NAI_RESERVED_NATIONAL = 2,
SCCP_NAI_NATIONAL_SIGNIFICANT = 3,
SCCP_NAI_INTERNATIONAL = 4,
};
struct sccp_global_title {
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t nature_of_addr_ind : 7,
odd_even : 1;
#elif __BYTE_ORDER == __BIG_ENDIAN
u_int8_t odd_even : 1,
nature_of_addr_ind : 7;
#endif
u_int8_t data[0];
} __attribute__((packed));
/* Q.713, 3.3 */
struct sccp_source_reference {
u_int8_t octet1;
u_int8_t octet2;
u_int8_t octet3;
} __attribute__((packed));
/* Q.714, 3.6 */
enum sccp_protocol_class {
SCCP_PROTOCOL_CLASS_0 = 0,
SCCP_PROTOCOL_CLASS_1 = 1,
SCCP_PROTOCOL_CLASS_2 = 2,
SCCP_PROTOCOL_CLASS_3 = 3,
};
/* bits 5-8 when class0, class1 is used */
enum sccp_protocol_options {
SCCP_PROTOCOL_NO_SPECIAL = 0,
SCCP_PROTOCOL_RETURN_MESSAGE = 8,
};
enum sccp_release_cause {
SCCP_RELEASE_CAUSE_END_USER_ORIGINATED = 0,
SCCP_RELEASE_CAUSE_END_USER_CONGESTION = 1,
SCCP_RELEASE_CAUSE_END_USER_FAILURE = 2,
SCCP_RELEASE_CAUSE_SCCP_USER_ORIGINATED = 3,
SCCP_RELEASE_CAUSE_REMOTE_PROCEDURE_ERROR = 4,
SCCP_RELEASE_CAUSE_INCONSISTENT_CONN_DATA = 5,
SCCP_RELEASE_CAUSE_ACCESS_FAILURE = 6,
SCCP_RELEASE_CAUSE_ACCESS_CONGESTION = 7,
SCCP_RELEASE_CAUSE_SUBSYSTEM_FAILURE = 8,
SCCP_RELEASE_CAUSE_SUBSYSTEM_CONGESTION = 9,
SCCP_RELEASE_CAUSE_MTP_FAILURE = 10,
SCCP_RELEASE_CAUSE_NETWORK_CONGESTION = 11,
SCCP_RELEASE_CAUSE_EXPIRATION_RESET = 12,
SCCP_RELEASE_CAUSE_EXPIRATION_INACTIVE = 13,
SCCP_RELEASE_CAUSE_RESERVED = 14,
SCCP_RELEASE_CAUSE_UNQUALIFIED = 15,
SCCP_RELEASE_CAUSE_SCCP_FAILURE = 16,
};
enum sccp_return_cause {
SCCP_RETURN_CAUSE_NO_TRANSLATION_NATURE = 0,
SCCP_RETURN_CAUSE_NO_TRANSLATION = 1,
SCCP_RETURN_CAUSE_SUBSYSTEM_CONGESTION = 2,
SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE = 3,
SCCP_RETURN_CAUSE_UNEQUIPPED_USER = 4,
SCCP_RETURN_CAUSE_MTP_FAILURE = 5,
SCCP_RETURN_CAUSE_NETWORK_CONGESTION = 6,
SCCP_RETURN_CAUSE_UNQUALIFIED = 7,
SCCP_RETURN_CAUSE_ERROR_IN_MSG_TRANSPORT = 8,
SCCP_RETURN_CAUSE_ERROR_IN_LOCAL_PROCESSING = 9,
SCCP_RETURN_CAUSE_DEST_CANNOT_PERFORM_REASSEMBLY = 10,
SCCP_RETURN_CAUSE_SCCP_FAILURE = 11,
SCCP_RETURN_CAUSE_HOP_COUNTER_VIOLATION = 12,
SCCP_RETURN_CAUSE_SEGMENTATION_NOT_SUPPORTED= 13,
SCCP_RETURN_CAUSE_SEGMENTATION_FAOLURE = 14
};
enum sccp_reset_cause {
SCCP_RESET_CAUSE_END_USER_ORIGINATED = 0,
SCCP_RESET_CAUSE_SCCP_USER_ORIGINATED = 1,
SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PS = 2,
SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PR = 3,
SCCP_RESET_CAUSE_RPC_OUT_OF_WINDOW = 4,
SCCP_RESET_CAUSE_RPC_INCORRECT_PS = 5,
SCCP_RESET_CAUSE_RPC_GENERAL = 6,
SCCP_RESET_CAUSE_REMOTE_END_USER_OPERATIONAL= 7,
SCCP_RESET_CAUSE_NETWORK_OPERATIONAL = 8,
SCCP_RESET_CAUSE_ACCESS_OPERATIONAL = 9,
SCCP_RESET_CAUSE_NETWORK_CONGESTION = 10,
SCCP_RESET_CAUSE_RESERVED = 11,
};
enum sccp_error_cause {
SCCP_ERROR_LRN_MISMATCH_UNASSIGNED = 0, /* local reference number */
SCCP_ERROR_LRN_MISMATCH_INCONSISTENT = 1,
SCCP_ERROR_POINT_CODE_MISMATCH = 2,
SCCP_ERROR_SERVICE_CLASS_MISMATCH = 3,
SCCP_ERROR_UNQUALIFIED = 4,
};
enum sccp_refusal_cause {
SCCP_REFUSAL_END_USER_ORIGINATED = 0,
SCCP_REFUSAL_END_USER_CONGESTION = 1,
SCCP_REFUSAL_END_USER_FAILURE = 2,
SCCP_REFUSAL_SCCP_USER_ORIGINATED = 3,
SCCP_REFUSAL_DESTINATION_ADDRESS_UKNOWN = 4,
SCCP_REFUSAL_DESTINATION_INACCESSIBLE = 5,
SCCP_REFUSAL_NET_QOS_NON_TRANSIENT = 6,
SCCP_REFUSAL_NET_QOS_TRANSIENT = 7,
SCCP_REFUSAL_ACCESS_FAILURE = 8,
SCCP_REFUSAL_ACCESS_CONGESTION = 9,
SCCP_REFUSAL_SUBSYSTEM_FAILURE = 10,
SCCP_REFUSAL_SUBSYTEM_CONGESTION = 11,
SCCP_REFUSAL_EXPIRATION = 12,
SCCP_REFUSAL_INCOMPATIBLE_USER_DATA = 13,
SCCP_REFUSAL_RESERVED = 14,
SCCP_REFUSAL_UNQUALIFIED = 15,
SCCP_REFUSAL_HOP_COUNTER_VIOLATION = 16,
SCCP_REFUSAL_SCCP_FAILURE = 17,
SCCP_REFUSAL_UNEQUIPPED_USER = 18,
};
/*
* messages... as of Q.713 Chapter 4
*/
struct sccp_connection_request {
/* mandantory */
u_int8_t type;
struct sccp_source_reference source_local_reference;
u_int8_t proto_class;
/* variable */
u_int8_t variable_called;
#if VARIABLE
called_party_address
#endif
/* optional */
u_int8_t optional_start;
#if OPTIONAL
credit 3
callingparty var 4-n
data 3-130
hop_counter 3
importance 3
end_of_optional 1
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_connection_confirm {
/* mandantory */
u_int8_t type;
struct sccp_source_reference destination_local_reference;
struct sccp_source_reference source_local_reference;
u_int8_t proto_class;
/* optional */
u_int8_t optional_start;
/* optional */
#if OPTIONAL
credit 3
called party 4
data 3-130
importance 3
end_of_optional 1
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_connection_refused {
/* mandantory */
u_int8_t type;
struct sccp_source_reference destination_local_reference;
u_int8_t cause;
/* optional */
u_int8_t optional_start;
/* optional */
#if OPTIONAL
called party 4
data 3-130
importance 3
end_of_optional 1
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_connection_released {
/* mandantory */
u_int8_t type;
struct sccp_source_reference destination_local_reference;
struct sccp_source_reference source_local_reference;
u_int8_t release_cause;
/* optional */
u_int8_t optional_start;
#if OPTIONAL
data 3-130
importance 3
end_of_optional 1
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_connection_release_complete {
u_int8_t type;
struct sccp_source_reference destination_local_reference;
struct sccp_source_reference source_local_reference;
} __attribute__((packed));
struct sccp_data_form1 {
/* mandantory */
u_int8_t type;
struct sccp_source_reference destination_local_reference;
u_int8_t segmenting;
/* variable */
u_int8_t variable_start;
#if VARIABLE
data 2-256;
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_data_unitdata {
/* mandantory */
u_int8_t type;
u_int8_t proto_class;
/* variable */
u_int8_t variable_called;
u_int8_t variable_calling;
u_int8_t variable_data;
#if VARIABLE
called party address
calling party address
#endif
u_int8_t data[0];
} __attribute__((packed));
struct sccp_data_it {
/* mandantory */
u_int8_t type;
struct sccp_source_reference destination_local_reference;
struct sccp_source_reference source_local_reference;
u_int8_t proto_class;
u_int8_t sequencing[2];
u_int8_t credit;
} __attribute__((packed));
struct sccp_proto_err {
u_int8_t type;
struct sccp_source_reference destination_local_reference;
u_int8_t error_cause;
};
#endif

View File

@@ -65,6 +65,7 @@ enum node_type {
VIEW_NODE, /* View node. Default mode of vty interface. */
AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
ENABLE_NODE, /* Enable node. */
OML_NODE,
CONFIG_NODE, /* Config node. Default mode of config file. */
SERVICE_NODE, /* Service node. */
DEBUG_NODE, /* Debug node. */

View File

@@ -1,10 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: OpenBSC SCCP Lib
Description: OpenBSC SCCP Lib
Version: @VERSION@
Libs: -L${libdir} -lsccp
Cflags: -I${includedir}/

View File

@@ -1,6 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOSCCP_LIBS)
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
isdnsync bsc_mgcp ipaccess-proxy \
@@ -8,11 +8,8 @@ sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a
noinst_HEADERS = vty/cardshell.h
bscdir = $(libdir)
bsc_LIBRARIES = libsccp.a
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
chan_alloc.c debug.c \
chan_alloc.c debug.c abis_nm_vty.c \
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \
input/misdn.c input/ipaccess.c \
@@ -27,16 +24,14 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c \
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
libsccp_a_SOURCES = sccp/sccp.c
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \
rs232.c bts_siemens_bs11.c
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \
bsc_msc.c bsc_msc_rf.c bsc_msc_grace.c gsm_04_80.c
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
bsc_msc.c osmo_bsc_rf.c osmo_bsc_grace.c gsm_04_80.c
bsc_msc_ip_LDADD = libbsc.a libvty.a $(LIBOSMOSCCP_LIBS)
ipaccess_find_SOURCES = ipaccess/ipaccess-find.c

View File

@@ -439,30 +439,30 @@ static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
static int abis_nm_rcvmsg_sw(struct msgb *mb);
static struct value_string obj_class_names[] = {
{ NM_OC_SITE_MANAGER, "SITE MANAGER" },
const struct value_string abis_nm_obj_class_names[] = {
{ NM_OC_SITE_MANAGER, "SITE-MANAGER" },
{ NM_OC_BTS, "BTS" },
{ NM_OC_RADIO_CARRIER, "RADIO CARRIER" },
{ NM_OC_BASEB_TRANSC, "BASEBAND TRANSCEIVER" },
{ NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
{ NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
{ NM_OC_CHANNEL, "CHANNEL" },
{ NM_OC_BS11_ADJC, "ADJC" },
{ NM_OC_BS11_HANDOVER, "HANDOVER" },
{ NM_OC_BS11_PWR_CTRL, "POWER CONTROL" },
{ NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
{ NM_OC_BS11_BTSE, "BTSE" },
{ NM_OC_BS11_RACK, "RACK" },
{ NM_OC_BS11_TEST, "TEST" },
{ NM_OC_BS11_ENVABTSE, "ENVABTSE" },
{ NM_OC_BS11_BPORT, "BPORT" },
{ NM_OC_GPRS_NSE, "GPRS NSE" },
{ NM_OC_GPRS_CELL, "GPRS CELL" },
{ NM_OC_GPRS_NSVC, "GPRS NSVC" },
{ NM_OC_GPRS_NSE, "GPRS-NSE" },
{ NM_OC_GPRS_CELL, "GPRS-CELL" },
{ NM_OC_GPRS_NSVC, "GPRS-NSVC" },
{ NM_OC_BS11, "SIEMENSHW" },
{ 0, NULL }
};
static const char *obj_class_name(u_int8_t oc)
{
return get_value_string(obj_class_names, oc);
return get_value_string(abis_nm_obj_class_names, oc);
}
const char *nm_opstate_name(u_int8_t os)
@@ -510,18 +510,17 @@ static struct value_string test_names[] = {
{ 0, NULL }
};
const struct value_string abis_nm_adm_state_names[] = {
{ NM_STATE_LOCKED, "Locked" },
{ NM_STATE_UNLOCKED, "Unlocked" },
{ NM_STATE_SHUTDOWN, "Shutdown" },
{ NM_STATE_NULL, "NULL" },
{ 0, NULL }
};
const char *nm_adm_name(u_int8_t adm)
{
switch (adm) {
case 1:
return "Locked";
case 2:
return "Unlocked";
case 3:
return "Shutdown";
default:
return "<not used>";
}
return get_value_string(abis_nm_adm_state_names, adm);
}
int nm_is_running(struct gsm_nm_state *s) {

194
openbsc/src/abis_nm_vty.c Normal file
View File

@@ -0,0 +1,194 @@
/* VTY interface for A-bis OML (Netowrk Management) */
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <openbsc/gsm_data.h>
#include <osmocore/msgb.h>
#include <osmocore/tlv.h>
#include <osmocore/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/signal.h>
#include <openbsc/abis_nm.h>
#include <openbsc/vty.h>
#include <vty/command.h>
extern struct gsm_network *bsc_gsmnet;
static struct cmd_node oml_node = {
OML_NODE,
"%s(oml)# ",
1,
};
struct oml_node_state {
struct gsm_bts *bts;
uint8_t obj_class;
uint8_t obj_inst[3];
};
static int dummy_config_write(struct vty *v)
{
return CMD_SUCCESS;
}
/* FIXME: auto-generate those strings from the value_string lists */
#define NM_OBJCLASS_VTY "(site-manager|bts|radio-carrier|baseband-transceiver|channel|adjc|handover|power-contorl|btse|rack|test|envabtse|bport|gprs-nse|gprs-cell|gprs-nsvc|siemenshw)"
#define NM_OBJCLASS_VTY_HELP "FIXME"
DEFUN(oml_class_inst, oml_class_inst_cmd,
"bts <0-255> oml class " NM_OBJCLASS_VTY
" instance <0-255> <0-255> <0-255>",
"BTS related commands\n" "BTS Number\n"
"Manipulate the OML managed objects\n"
"Object Class\n" NM_OBJCLASS_VTY_HELP
"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
{
struct gsm_bts *bts;
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
}
oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
if (!oms)
return CMD_WARNING;
oms->bts = bts;
oms->obj_class = get_string_value(abis_nm_obj_class_names, argv[1]);
oms->obj_inst[0] = atoi(argv[2]);
oms->obj_inst[1] = atoi(argv[3]);
oms->obj_inst[2] = atoi(argv[4]);
vty->index = oms;
vty->node = OML_NODE;
return CMD_SUCCESS;
}
DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
"bts <0-255> oml class <0-255> instance <0-255> <0-255> <0-255>",
"BTS related commands\n" "BTS Number\n"
"Manipulate the OML managed objects\n"
"Object Class\n" "Object Class\n"
"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
{
struct gsm_bts *bts;
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
}
oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
if (!oms)
return CMD_WARNING;
oms->bts = bts;
oms->obj_class = atoi(argv[1]);
oms->obj_inst[0] = atoi(argv[2]);
oms->obj_inst[1] = atoi(argv[3]);
oms->obj_inst[2] = atoi(argv[4]);
vty->index = oms;
vty->node = OML_NODE;
return CMD_SUCCESS;
}
DEFUN(oml_attrib_get, oml_attrib_get_cmd,
"attribute get <0-255>",
"OML Attribute Actions\n" "Get a single OML Attribute\n"
"OML Attribute Number\n")
{
struct oml_node_state *oms = vty->index;
/* FIXME */
return CMD_SUCCESS;
}
DEFUN(oml_attrib_set, oml_attrib_set_cmd,
"attribute set <0-255> .HEX",
"OML Attribute Actions\n" "Set a single OML Attribute\n"
"OML Attribute Number\n")
{
struct oml_node_state *oms = vty->index;
/* FIXME */
return CMD_SUCCESS;
}
DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd,
"change-adm-state (locked|unlocked|shutdown|null)",
"Change the Administrative State\n"
"Locked\n" "Unlocked\n" "Shutdown\n" "NULL\n")
{
struct oml_node_state *oms = vty->index;
enum abis_nm_adm_state state;
state = get_string_value(abis_nm_adm_state_names, argv[0]);
abis_nm_chg_adm_state(oms->bts, oms->obj_class, oms->obj_inst[0],
oms->obj_inst[1], oms->obj_inst[2], state);
return CMD_SUCCESS;
}
DEFUN(oml_opstart, oml_opstart_cmd,
"opstart", "Send an OPSTART message to the object")
{
struct oml_node_state *oms = vty->index;
abis_nm_opstart(oms->bts, oms->obj_class, oms->obj_inst[0],
oms->obj_inst[1], oms->obj_inst[2]);
return CMD_SUCCESS;
}
int abis_nm_vty_init(void)
{
install_element(ENABLE_NODE, &oml_class_inst_cmd);
install_element(ENABLE_NODE, &oml_classnum_inst_cmd);
install_node(&oml_node, dummy_config_write);
install_default(OML_NODE);
install_element(OML_NODE, &oml_attrib_get_cmd);
install_element(OML_NODE, &oml_attrib_set_cmd);
install_element(OML_NODE, &oml_chg_adm_state_cmd);
install_element(OML_NODE, &oml_opstart_cmd);
return 0;
}

View File

@@ -33,6 +33,7 @@
#include <openbsc/signal.h>
#include <openbsc/chan_alloc.h>
#include <osmocore/talloc.h>
#include <openbsc/ipaccess.h>
/* global pointer to the gsm network data structure */
extern struct gsm_network *bsc_gsmnet;
@@ -469,8 +470,6 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
sizeof(nanobts_attr_nse));
abis_nm_opstart(bts, obj_class, bts->bts_nr,
0xff, 0xff);
abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
0xff, 0xff, NM_STATE_UNLOCKED);
}
break;
case NM_OC_GPRS_CELL:
@@ -485,6 +484,8 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
0, 0xff);
abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
0, 0xff, NM_STATE_UNLOCKED);
abis_nm_chg_adm_state(bts, NM_OC_GPRS_NSE, bts->bts_nr,
0xff, 0xff, NM_STATE_UNLOCKED);
}
break;
case NM_OC_GPRS_NSVC:
@@ -563,10 +564,19 @@ static int sw_activ_rep(struct msgb *mb)
/* Callback function for NACK on the OML NM */
static int oml_msg_nack(u_int8_t mt)
{
int i;
if (mt == NM_MT_SET_BTS_ATTR_NACK) {
LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. "
"Was the bts type and frequency properly specified?\n");
exit(-1);
} else {
LOGP(DNM, LOGL_ERROR, "Got a NACK going to drop the OML links.\n");
for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
if (is_ipaccess_bts(bts))
ipaccess_drop_oml(bts);
}
}
return 0;

View File

@@ -58,20 +58,6 @@ static void msc_con_timeout(void *_con)
bsc_msc_lost(con);
}
static int bsc_msc_except(struct bsc_fd *bfd)
{
struct write_queue *wrt;
struct bsc_msc_connection *con;
LOGP(DMSC, LOGL_ERROR, "Exception on the BFD. Closing down.\n");
wrt = container_of(bfd, struct write_queue, bfd);
con = container_of(wrt, struct bsc_msc_connection, write_queue);
connection_loss(con);
return 0;
}
/* called in the case of a non blocking connect */
static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
{
@@ -83,13 +69,16 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
socklen_t len = sizeof(val);
if ((what & BSC_FD_WRITE) == 0) {
LOGP(DMSC, LOGL_ERROR, "Callback but not readable.\n");
LOGP(DMSC, LOGL_ERROR, "Callback but not writable.\n");
return -1;
}
queue = container_of(fd, struct write_queue, bfd);
con = container_of(queue, struct bsc_msc_connection, write_queue);
/* From here on we will either be connected or reconnect */
bsc_del_timer(&con->timeout_timer);
/* check the socket state */
rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
if (rc != 0) {
@@ -107,7 +96,6 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
con->is_connected = 1;
bsc_del_timer(&con->timeout_timer);
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
if (con->connected)
con->connected(con);
@@ -222,14 +210,16 @@ struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio)
con->port = port;
con->prio = prio;
write_queue_init(&con->write_queue, 100);
con->write_queue.except_cb = bsc_msc_except;
return con;
}
void bsc_msc_lost(struct bsc_msc_connection *con)
{
write_queue_clear(&con->write_queue);
bsc_unregister_fd(&con->write_queue.bfd);
bsc_del_timer(&con->timeout_timer);
if (con->write_queue.bfd.fd >= 0)
bsc_unregister_fd(&con->write_queue.bfd);
connection_loss(con);
}

View File

@@ -45,15 +45,15 @@
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_msc_rf.h>
#include <openbsc/bsc_msc_grace.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/osmo_bsc_grace.h>
#include <osmocore/select.h>
#include <osmocore/talloc.h>
#include <osmocore/write_queue.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
#include <osmocom/sccp/sccp.h>
/* SCCP helper */
#define SCCP_IT_TIMER 60
@@ -326,6 +326,9 @@ static int open_sccp_connection(struct msgb *layer3)
con_data->lchan = layer3->lchan;
con_data->sccp = sccp_connection;
/* assign the outgoing msc connection */
con_data->msc_con = bsc_gsmnet->msc_con;
sccp_connection->state_cb = msc_outgoing_sccp_state;
sccp_connection->data_cb = msc_outgoing_sccp_data;
sccp_connection->data_ctx = con_data;
@@ -541,6 +544,38 @@ static int handle_modify_ack(struct msgb *msg)
return 1;
}
/*
* Check if the subscriber is coming from our LAC
*/
static void handle_lu(struct msgb *msg)
{
struct gsm48_hdr *gh;
struct gsm48_loc_upd_req *lu;
struct gsm48_loc_area_id lai;
struct gsm_network *net;
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
return;
}
if (!msg->lchan->msc_data)
return;
net = msg->trx->bts->network;
gh = msgb_l3(msg);
lu = (struct gsm48_loc_upd_req *) gh->data;
gsm48_generate_lai(&lai, net->country_code, net->network_code,
msg->trx->bts->location_area_code);
if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
msg->lchan->msc_data->new_subscriber = 1;
}
}
/* Receive a GSM 04.08 Radio Resource (RR) message */
static int gsm0408_rcv_rr(struct msgb *msg)
{
@@ -586,6 +621,8 @@ static int gsm0408_rcv_mm(struct msgb *msg)
case GSM48_MT_MM_CM_SERV_REQ:
case GSM48_MT_MM_IMSI_DETACH_IND:
rc = send_dtap_or_open_connection(msg);
if ((gh->msg_type & 0xbf) == GSM48_MT_MM_LOC_UPD_REQUEST)
handle_lu(msg);
break;
default:
break;
@@ -709,7 +746,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
return ret;
}
static void msc_sccp_write_ipa(struct msgb *msg, void *data)
static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg, void *data)
{
msc_queue_write(msg, IPAC_PROTO_SCCP);
}
@@ -1141,7 +1178,7 @@ static void signal_handler(int signal)
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!bsc_gsmnet->msc_con || !bsc_gsmnet->msc_con->is_connected)
if (!bsc_gsmnet->msc_con)
return;
bsc_msc_lost(bsc_gsmnet->msc_con);
break;
@@ -1230,6 +1267,7 @@ int main(int argc, char **argv)
}
/* initialize sccp */
sccp_set_log_area(DSCCP);
sccp_system_init(msc_sccp_write_ipa, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL);
@@ -1245,7 +1283,7 @@ int main(int argc, char **argv)
}
if (rf_ctl) {
bsc_gsmnet->rf = bsc_msc_rf_create(rf_ctl, bsc_gsmnet);
bsc_gsmnet->rf = osmo_bsc_rf_create(rf_ctl, bsc_gsmnet);
if (!bsc_gsmnet->rf) {
fprintf(stderr, "Failed to create the RF service.\n");
exit(1);

View File

@@ -1,6 +1,6 @@
/* GSM 08.08 BSSMAP handling */
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by On-Waves
/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,11 @@
#include <openbsc/signal.h>
#include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/gsm_04_80.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
#include <osmocom/sccp/sccp.h>
#include <arpa/inet.h>
#include <assert.h>
@@ -45,9 +46,9 @@
static void bts_queue_send(struct msgb *msg, int link_id);
static void bssmap_free_secondary(struct bss_sccp_connection_data *data);
static uint32_t read_data32(const uint8_t *data)
static uint16_t read_data16(const uint8_t *data)
{
uint32_t res;
uint16_t res;
memcpy(&res, data, sizeof(res));
return res;
@@ -73,6 +74,19 @@ static int bssmap_paging_cb(unsigned int hooknum, unsigned int event, struct msg
return 0;
}
/* Send a USSD message */
static void send_welcome_ussd(struct gsm_lchan *lchan)
{
struct gsm_network *network;
network = lchan->ts->trx->bts->network;
if (!network->ussd_welcome_txt)
return;
gsm0480_send_ussdNotify(lchan, 1, network->ussd_welcome_txt);
gsm0480_send_releaseComplete(lchan);
}
static int bssmap_handle_reset_ack(struct gsm_network *net, struct msgb *msg, unsigned int length)
{
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
@@ -131,7 +145,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
* Support paging to all network or one BTS at one LAC
*/
if (data_length == 3 && data[0] == CELL_IDENT_LAC) {
lac = ntohs(read_data32(&data[1]));
lac = ntohs(read_data16(&data[1]));
} else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
return -1;
@@ -513,7 +527,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
goto reject;
}
cic = ntohs(*(u_int16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)));
timeslot = cic & 0x1f;
multiplex = (cic & ~0x1f) >> 5;
@@ -663,6 +677,7 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
struct msgb *gsm48;
u_int8_t *data;
u_int8_t link_id;
int is_lu = 0;
if (!lchan) {
LOGP(DMSC, LOGL_ERROR, "No lchan available\n");
@@ -712,6 +727,7 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
gsm48_generate_lai(lai, net->country_code,
net->network_code,
gsm48->trx->bts->location_area_code);
is_lu = 1;
}
}
}
@@ -724,6 +740,11 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
link_id |= 0x40;
bts_queue_send(gsm48, link_id);
/* Feature to send a welcome USSD for a new subscriber */
if (is_lu && lchan->msc_data->new_subscriber)
send_welcome_ussd(lchan);
return 0;
}

View File

@@ -52,6 +52,7 @@
#include <openbsc/transaction.h>
#include <openbsc/ussd.h>
#include <openbsc/silent_call.h>
#include <osmocore/gsm0480.h>
void *tall_locop_ctx;

View File

@@ -36,17 +36,7 @@
#include <osmocore/gsm_utils.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_04_80.h>
/* Forward declarations */
static int parse_ussd(u_int8_t *ussd, struct ussd_request *req);
static int parse_ussd_info_elements(u_int8_t *ussd_ie,
struct ussd_request *req);
static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length,
struct ussd_request *req);
static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
struct ussd_request *req);
static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
struct ussd_request *req);
#include <osmocore/gsm0480.h>
static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag)
{
@@ -69,291 +59,6 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag,
}
/* Decode a mobile-originated USSD-request message */
int gsm0480_decode_ussd_request(const struct msgb *msg, struct ussd_request *req)
{
int rc = 0;
u_int8_t *parse_ptr = msgb_l3(msg);
if ((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) {
req->transaction_id = *parse_ptr & 0x70;
rc = parse_ussd(parse_ptr+1, req);
}
if (!rc)
DEBUGP(DMM, "Error occurred while parsing received USSD!\n");
return rc;
}
static int parse_ussd(u_int8_t *ussd, struct ussd_request *req)
{
int rc = 1;
u_int8_t msg_type = ussd[0] & 0xBF; /* message-type - section 3.4 */
switch (msg_type) {
case GSM0480_MTYPE_RELEASE_COMPLETE:
DEBUGP(DMM, "USS Release Complete\n");
/* could also parse out the optional Cause/Facility data */
req->text[0] = 0xFF;
break;
case GSM0480_MTYPE_REGISTER:
case GSM0480_MTYPE_FACILITY:
rc &= parse_ussd_info_elements(ussd+1, req);
break;
default:
fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n",
ussd[0]);
rc = 0;
break;
}
return rc;
}
static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req)
{
int rc;
/* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */
u_int8_t iei = ussd_ie[0];
u_int8_t iei_length = ussd_ie[1];
switch (iei) {
case GSM48_IE_CAUSE:
break;
case GSM0480_IE_FACILITY:
rc = parse_facility_ie(ussd_ie+2, iei_length, req);
break;
case GSM0480_IE_SS_VERSION:
break;
default:
fprintf(stderr, "Unhandled GSM 04.08 or 04.80 IEI 0x%02x\n",
iei);
rc = 0;
break;
}
return rc;
}
static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length,
struct ussd_request *req)
{
int rc = 1;
u_int8_t offset = 0;
do {
/* Component Type tag - table 3.7 */
u_int8_t component_type = facility_ie[offset];
u_int8_t component_length = facility_ie[offset+1];
switch (component_type) {
case GSM0480_CTYPE_INVOKE:
rc &= parse_ss_invoke(facility_ie+2,
component_length,
req);
break;
case GSM0480_CTYPE_RETURN_RESULT:
break;
case GSM0480_CTYPE_RETURN_ERROR:
break;
case GSM0480_CTYPE_REJECT:
break;
default:
fprintf(stderr, "Unknown GSM 04.80 Facility "
"Component Type 0x%02x\n", component_type);
rc = 0;
break;
}
offset += (component_length+2);
} while (offset < length);
return rc;
}
/* Parse an Invoke component - see table 3.3 */
static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
struct ussd_request *req)
{
int rc = 1;
u_int8_t offset;
/* mandatory part */
if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) {
fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag "
"0x%02x (expecting Invoke ID tag)\n", invoke_data[0]);
}
offset = invoke_data[1] + 2;
req->invoke_id = invoke_data[2];
/* optional part */
if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID)
offset += invoke_data[offset+1] + 2; /* skip over it */
/* mandatory part */
if (invoke_data[offset] == GSM0480_OPERATION_CODE) {
u_int8_t operation_code = invoke_data[offset+2];
switch (operation_code) {
case GSM0480_OP_CODE_PROCESS_USS_REQ:
rc = parse_process_uss_req(invoke_data + offset + 3,
length - offset - 3,
req);
break;
default:
fprintf(stderr, "GSM 04.80 operation code 0x%02x "
"is not yet handled\n", operation_code);
rc = 0;
break;
}
} else {
fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x "
"(expecting Operation Code tag)\n",
invoke_data[0]);
rc = 0;
}
return rc;
}
/* Parse the parameters of a Process UnstructuredSS Request */
static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
struct ussd_request *req)
{
int rc = 0;
int num_chars;
u_int8_t dcs;
if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) {
if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) {
dcs = uss_req_data[4];
if ((dcs == 0x0F) &&
(uss_req_data[5] == ASN1_OCTET_STRING_TAG)) {
num_chars = (uss_req_data[6] * 8) / 7;
/* Prevent a mobile-originated buffer-overrun! */
if (num_chars > MAX_LEN_USSD_STRING)
num_chars = MAX_LEN_USSD_STRING;
gsm_7bit_decode(req->text,
&(uss_req_data[7]), num_chars);
/* append null-terminator */
req->text[num_chars+1] = 0;
rc = 1;
}
}
}
return rc;
}
struct msgb *gsm0480_create_notifySS(const char *text)
{
struct msgb *msg;
uint8_t *data, *tmp_len;
uint8_t *seq_len_ptr, *cal_len_ptr, *opt_len_ptr, *nam_len_ptr;
int len;
len = strlen(text);
if (len < 1 || len > 160)
return NULL;
msg = gsm48_msgb_alloc();
if (!msg)
return NULL;
msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG);
seq_len_ptr = msgb_put(msg, 1);
/* ss_code for CNAP { */
msgb_put_u8(msg, 0x81);
msgb_put_u8(msg, 1);
msgb_put_u8(msg, 0x19);
/* } ss_code */
/* nameIndicator { */
msgb_put_u8(msg, 0xB4);
nam_len_ptr = msgb_put(msg, 1);
/* callingName { */
msgb_put_u8(msg, 0xA0);
opt_len_ptr = msgb_put(msg, 1);
msgb_put_u8(msg, 0xA0);
cal_len_ptr = msgb_put(msg, 1);
/* namePresentationAllowed { */
/* add the DCS value */
msgb_put_u8(msg, 0x80);
msgb_put_u8(msg, 1);
msgb_put_u8(msg, 0x0F);
/* add the lengthInCharacters */
msgb_put_u8(msg, 0x81);
msgb_put_u8(msg, 1);
msgb_put_u8(msg, strlen(text));
/* add the actual string */
msgb_put_u8(msg, 0x82);
tmp_len = msgb_put(msg, 1);
data = msgb_put(msg, 0);
len = gsm_7bit_encode(data, text);
tmp_len[0] = len;
msgb_put(msg, len);
/* }; namePresentationAllowed */
cal_len_ptr[0] = 3 + 3 + 2 + len;
opt_len_ptr[0] = cal_len_ptr[0] + 2;
/* }; callingName */
nam_len_ptr[0] = opt_len_ptr[0] + 2;
/* ); nameIndicator */
/* write the lengths... */
seq_len_ptr[0] = 3 + nam_len_ptr[0] + 2;
return msg;
}
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text)
{
struct msgb *msg;
uint8_t *seq_len_ptr, *ussd_len_ptr, *data;
int len;
msg = gsm48_msgb_alloc();
if (!msg)
return NULL;
/* SEQUENCE { */
msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG);
seq_len_ptr = msgb_put(msg, 1);
/* DCS { */
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
msgb_put_u8(msg, 1);
msgb_put_u8(msg, 0x0F);
/* } DCS */
/* USSD-String { */
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
ussd_len_ptr = msgb_put(msg, 1);
data = msgb_put(msg, 0);
len = gsm_7bit_encode(data, text);
msgb_put(msg, len);
ussd_len_ptr[0] = len;
/* USSD-String } */
/* alertingPattern { */
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
msgb_put_u8(msg, 1);
msgb_put_u8(msg, alertPattern);
/* } alertingPattern */
seq_len_ptr[0] = 3 + 2 + ussd_len_ptr[0] + 3;
/* } SEQUENCE */
return msg;
}
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_text,
const struct ussd_request *req)
@@ -407,35 +112,6 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_t
return gsm48_sendmsg(msg, NULL);
}
/* wrap an invoke around it... the other way around
*
* 1.) Invoke Component tag
* 2.) Invoke ID Tag
* 3.) Operation
* 4.) Data
*/
int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id)
{
/* 3. operation */
msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, op);
/* 2. invoke id tag */
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, link_id);
/* 1. component tag */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_INVOKE);
return 0;
}
/* wrap the GSM 04.08 Facility IE around it */
int gsm0480_wrap_facility(struct msgb *msg)
{
msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
return 0;
}
int gsm0480_send_ussd_reject(const struct msgb *in_msg,
const struct ussd_request *req)
{

View File

@@ -573,7 +573,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
e1i_ts->sign.tx_timer.data = e1i_ts;
/* Reducing this might break the nanoBTS 900 init. */
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 0);
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
@@ -607,7 +607,7 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
struct e1inp_driver ipaccess_driver = {
.name = "ip.access",
.want_write = ts_want_write,
.default_delay = 100000,
.default_delay = 0,
};
/* callback of the OML listening filedescriptor */

View File

@@ -128,7 +128,7 @@ static int mgcp_rsip_cb(struct mgcp_config *cfg)
return 0;
}
static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state, int local_rtp)
static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state)
{
if (state != MGCP_ENDP_MDCX)
return 0;

View File

@@ -90,11 +90,12 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp)
{
static char buf[] = { DUMMY_LOAD };
return udp_send(endp->local_rtp.fd, &endp->remote,
endp->net_rtp, buf, 1);
return udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
endp->net_end.rtp_port, buf, 1);
}
static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *data, int len)
static void patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
int payload, struct sockaddr_in *addr, char *data, int len)
{
uint16_t seq;
uint32_t timestamp;
@@ -116,9 +117,11 @@ static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *dat
state->ssrc = rtp_hdr->ssrc;
state->seq_offset = (state->seq_no + 1) - seq;
state->timestamp_offset = state->last_timestamp - timestamp;
state->patch = 1;
LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed... SSRC: %u offset: %d\n",
state->ssrc, state->seq_offset);
state->patch = endp->allow_patch;
LOGP(DMGCP, LOGL_NOTICE,
"The SSRC changed on 0x%x SSRC: %u offset: %d from %s:%d in %d\n",
ENDPOINT_NUMBER(endp), state->ssrc, state->seq_offset,
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode);
}
/* apply the offset and store it back to the packet */
@@ -145,87 +148,21 @@ static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *dat
}
/*
* There is data coming. We will have to figure out if it
* came from the BTS or the MediaGateway of the MSC. On top
* of that we need to figure out if it was RTP or RTCP.
*
* Currently we do not communicate with the BSC so we have
* no idea where the BTS is listening for RTP and need to
* do the classic routing trick. Wait for the first packet
* from the BTS and then go ahead.
* The below code is for dispatching. We have a dedicated port for
* the data coming from the net and one to discover the BTS.
*/
static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf, int len)
{
char buf[4096];
struct sockaddr_in addr;
socklen_t slen = sizeof(addr);
struct mgcp_endpoint *endp;
struct mgcp_config *cfg;
int rc, dest, proto;
endp = (struct mgcp_endpoint *) fd->data;
cfg = endp->cfg;
rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
(struct sockaddr *) &addr, &slen);
if (rc < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
ENDPOINT_NUMBER(endp), errno, strerror(errno));
return -1;
}
/* do not forward aynthing... maybe there is a packet from the bts */
if (endp->ci == CI_UNUSED) {
LOGP(DMGCP, LOGL_DEBUG, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
return -1;
}
/*
* Figure out where to forward it to. This code assumes that we
* have received the Connection Modify and know who is a legitimate
* partner. According to the spec we could attempt to forward even
* after the Create Connection but we will not as we are not really
* able to tell if this is legitimate.
*/
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
? DEST_BTS : DEST_NETWORK;
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
/* We have no idea who called us, maybe it is the BTS. */
if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
/* it was the BTS... */
if (!cfg->bts_ip
|| memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0
|| memcmp(&addr.sin_addr, &endp->bts, sizeof(endp->bts)) == 0) {
if (fd == &endp->local_rtp) {
endp->bts_rtp = addr.sin_port;
} else {
endp->bts_rtcp = addr.sin_port;
}
endp->bts = addr.sin_addr;
LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
inet_ntoa(addr.sin_addr));
}
}
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
ENDPOINT_NUMBER(endp));
if (!tap->enabled)
return 0;
}
/* do this before the loop handling */
if (dest == DEST_NETWORK)
++endp->in_bts;
else
++endp->in_remote;
return sendto(fd, buf, len, 0,
(struct sockaddr *)&tap->forward, sizeof(tap->forward));
}
static int send_to(struct mgcp_endpoint *endp, int dest, int is_rtp,
struct sockaddr_in *addr, char *buf, int rc)
{
struct mgcp_config *cfg = endp->cfg;
/* For loop toggle the destination and then dispatch. */
if (cfg->audio_loop)
dest = !dest;
@@ -235,22 +172,176 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
dest = !dest;
if (dest == DEST_NETWORK) {
if (proto == PROTO_RTP)
patch_and_count(&endp->bts_state,
endp->net_payload_type, buf, rc);
return udp_send(fd->fd, &endp->remote,
proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
buf, rc);
if (is_rtp) {
patch_and_count(endp, &endp->bts_state,
endp->net_end.payload_type,
addr, buf, rc);
forward_data(endp->net_end.rtp.fd,
&endp->taps[MGCP_TAP_NET_OUT], buf, rc);
return udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
endp->net_end.rtp_port, buf, rc);
} else {
return udp_send(endp->net_end.rtcp.fd, &endp->net_end.addr,
endp->net_end.rtcp_port, buf, rc);
}
} else {
if (proto == PROTO_RTP)
patch_and_count(&endp->net_state,
endp->bts_payload_type, buf, rc);
return udp_send(fd->fd, &endp->bts,
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
buf, rc);
if (is_rtp) {
patch_and_count(endp, &endp->net_state,
endp->bts_end.payload_type,
addr, buf, rc);
forward_data(endp->bts_end.rtp.fd,
&endp->taps[MGCP_TAP_BTS_OUT], buf, rc);
return udp_send(endp->bts_end.rtp.fd, &endp->bts_end.addr,
endp->bts_end.rtp_port, buf, rc);
} else {
return udp_send(endp->bts_end.rtcp.fd, &endp->bts_end.addr,
endp->bts_end.rtcp_port, buf, rc);
}
}
}
static int recevice_from(struct mgcp_endpoint *endp, int fd, struct sockaddr_in *addr,
char *buf, int bufsize)
{
int rc;
socklen_t slen = sizeof(*addr);
rc = recvfrom(fd, buf, bufsize, 0,
(struct sockaddr *) addr, &slen);
if (rc < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
ENDPOINT_NUMBER(endp), errno, strerror(errno));
return -1;
}
/* do not forward aynthing... maybe there is a packet from the bts */
if (!endp->allocated)
return -1;
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
return rc;
}
static int rtp_data_net(struct bsc_fd *fd, unsigned int what)
{
char buf[4096];
struct sockaddr_in addr;
struct mgcp_endpoint *endp;
int rc, proto;
endp = (struct mgcp_endpoint *) fd->data;
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
if (rc <= 0)
return -1;
if (memcmp(&addr.sin_addr, &endp->net_end.addr, sizeof(addr.sin_addr)) != 0) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong address %s on 0x%x\n",
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
return -1;
}
if (endp->net_end.rtp_port != addr.sin_port &&
endp->net_end.rtcp_port != addr.sin_port) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong source port %d on 0x%x\n",
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
return -1;
}
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from network on 0x%x\n",
ENDPOINT_NUMBER(endp));
return 0;
}
proto = fd == &endp->net_end.rtp ? PROTO_RTP : PROTO_RTCP;
endp->net_end.packets += 1;
forward_data(fd->fd, &endp->taps[MGCP_TAP_NET_IN], buf, rc);
return send_to(endp, DEST_BTS, proto == PROTO_RTP, &addr, &buf[0], rc);
}
static void discover_bts(struct mgcp_endpoint *endp, int proto, struct sockaddr_in *addr)
{
struct mgcp_config *cfg = endp->cfg;
if (proto == PROTO_RTP && endp->bts_end.rtp_port == 0) {
if (!cfg->bts_ip ||
memcmp(&addr->sin_addr,
&cfg->bts_in, sizeof(cfg->bts_in)) == 0 ||
memcmp(&addr->sin_addr,
&endp->bts_end.addr, sizeof(endp->bts_end.addr)) == 0) {
endp->bts_end.rtp_port = addr->sin_port;
endp->bts_end.addr = addr->sin_addr;
LOGP(DMGCP, LOGL_NOTICE,
"Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
ENDPOINT_NUMBER(endp), ntohs(endp->bts_end.rtp_port),
ntohs(endp->bts_end.rtcp_port), inet_ntoa(addr->sin_addr));
}
} else if (proto == PROTO_RTCP && endp->bts_end.rtcp_port == 0) {
if (memcmp(&endp->bts_end.addr, &addr->sin_addr,
sizeof(endp->bts_end.addr)) == 0) {
endp->bts_end.rtcp_port = addr->sin_port;
}
}
}
static int rtp_data_bts(struct bsc_fd *fd, unsigned int what)
{
char buf[4096];
struct sockaddr_in addr;
struct mgcp_endpoint *endp;
struct mgcp_config *cfg;
int rc, proto;
endp = (struct mgcp_endpoint *) fd->data;
cfg = endp->cfg;
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
if (rc <= 0)
return -1;
proto = fd == &endp->bts_end.rtp ? PROTO_RTP : PROTO_RTCP;
/* We have no idea who called us, maybe it is the BTS. */
/* it was the BTS... */
discover_bts(endp, proto, &addr);
if (memcmp(&endp->bts_end.addr, &addr.sin_addr, sizeof(addr.sin_addr)) != 0) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong bts %s on 0x%x\n",
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
return -1;
}
if (endp->bts_end.rtp_port != addr.sin_port &&
endp->bts_end.rtcp_port != addr.sin_port) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong bts source port %d on 0x%x\n",
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
return -1;
}
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from bts on 0x%x\n",
ENDPOINT_NUMBER(endp));
return 0;
}
/* do this before the loop handling */
endp->bts_end.packets += 1;
forward_data(fd->fd, &endp->taps[MGCP_TAP_BTS_IN], buf, rc);
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
}
static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
{
struct sockaddr_in addr;
@@ -269,6 +360,8 @@ static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
inet_aton(source_addr, &addr.sin_addr);
if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(fd->fd);
fd->fd = -1;
return -1;
}
@@ -283,59 +376,96 @@ static int set_ip_tos(int fd, int tos)
return ret != 0;
}
static int bind_rtp(struct mgcp_endpoint *endp)
static int bind_rtp(struct mgcp_config *cfg, struct mgcp_rtp_end *rtp_end, int endpno)
{
struct mgcp_config *cfg = endp->cfg;
if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
if (create_bind(cfg->source_addr, &rtp_end->rtp, rtp_end->local_port) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
cfg->source_addr, rtp_end->local_port, endpno);
goto cleanup0;
}
if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
if (create_bind(cfg->source_addr, &rtp_end->rtcp, rtp_end->local_port + 1) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
cfg->source_addr, rtp_end->local_port + 1, endpno);
goto cleanup1;
}
set_ip_tos(endp->local_rtp.fd, cfg->endp_dscp);
set_ip_tos(endp->local_rtcp.fd, cfg->endp_dscp);
set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
endp->local_rtp.cb = rtp_data_cb;
endp->local_rtp.data = endp;
endp->local_rtp.when = BSC_FD_READ;
if (bsc_register_fd(&endp->local_rtp) != 0) {
rtp_end->rtp.when = BSC_FD_READ;
if (bsc_register_fd(&rtp_end->rtp) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
endp->rtp_port, ENDPOINT_NUMBER(endp));
rtp_end->local_port, endpno);
goto cleanup2;
}
endp->local_rtcp.cb = rtp_data_cb;
endp->local_rtcp.data = endp;
endp->local_rtcp.when = BSC_FD_READ;
if (bsc_register_fd(&endp->local_rtcp) != 0) {
rtp_end->rtcp.when = BSC_FD_READ;
if (bsc_register_fd(&rtp_end->rtcp) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
rtp_end->local_port + 1, endpno);
goto cleanup3;
}
return 0;
cleanup3:
bsc_unregister_fd(&endp->local_rtp);
bsc_unregister_fd(&rtp_end->rtp);
cleanup2:
close(endp->local_rtcp.fd);
endp->local_rtcp.fd = -1;
close(rtp_end->rtcp.fd);
rtp_end->rtcp.fd = -1;
cleanup1:
close(endp->local_rtp.fd);
endp->local_rtp.fd = -1;
close(rtp_end->rtp.fd);
rtp_end->rtp.fd = -1;
cleanup0:
return -1;
}
int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
{
endp->rtp_port = rtp_port;
return bind_rtp(endp);
if (endp->bts_end.rtp.fd != -1 || endp->bts_end.rtcp.fd != -1) {
LOGP(DMGCP, LOGL_ERROR, "Previous bts-port was still bound on %d\n",
ENDPOINT_NUMBER(endp));
mgcp_free_rtp_port(&endp->bts_end);
}
endp->bts_end.local_port = rtp_port;
endp->bts_end.rtp.cb = rtp_data_bts;
endp->bts_end.rtp.data = endp;
endp->bts_end.rtcp.data = endp;
endp->bts_end.rtcp.cb = rtp_data_bts;
return bind_rtp(endp->cfg, &endp->bts_end, ENDPOINT_NUMBER(endp));
}
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
{
if (endp->net_end.rtp.fd != -1 || endp->net_end.rtcp.fd != -1) {
LOGP(DMGCP, LOGL_ERROR, "Previous net-port was still bound on %d\n",
ENDPOINT_NUMBER(endp));
mgcp_free_rtp_port(&endp->net_end);
}
endp->net_end.local_port = rtp_port;
endp->net_end.rtp.cb = rtp_data_net;
endp->net_end.rtp.data = endp;
endp->net_end.rtcp.data = endp;
endp->net_end.rtcp.cb = rtp_data_net;
return bind_rtp(endp->cfg, &endp->net_end, ENDPOINT_NUMBER(endp));
}
int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp.fd != -1) {
close(end->rtp.fd);
end->rtp.fd = -1;
bsc_unregister_fd(&end->rtp);
}
if (end->rtcp.fd != -1) {
close(end->rtcp.fd);
end->rtcp.fd = -1;
bsc_unregister_fd(&end->rtcp);
}
return 0;
}

View File

@@ -72,6 +72,7 @@
} \
}
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
struct mgcp_request {
char *name;
@@ -88,7 +89,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
static int generate_call_id(struct mgcp_config *cfg)
static uint32_t generate_call_id(struct mgcp_config *cfg)
{
int i;
@@ -169,13 +170,13 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
addr = endp->cfg->source_addr;
snprintf(sdp_record, sizeof(sdp_record) - 1,
"I: %d\n\n"
"I: %u\n\n"
"v=0\r\n"
"c=IN IP4 %s\r\n"
"m=audio %d RTP/AVP %d\r\n"
"a=rtpmap:%d %s\r\n",
endp->ci, addr, endp->rtp_port,
endp->bts_payload_type, endp->bts_payload_type,
endp->ci, addr, endp->net_end.local_port,
endp->bts_end.payload_type, endp->bts_end.payload_type,
endp->cfg->audio_name);
return mgcp_create_response_with_data(200, msg, trans_id, sdp_record);
}
@@ -323,11 +324,13 @@ static int verify_call_id(const struct mgcp_endpoint *endp,
}
static int verify_ci(const struct mgcp_endpoint *endp,
const char *ci)
const char *_ci)
{
if (atoi(ci) != endp->ci) {
LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
ENDPOINT_NUMBER(endp), endp->ci, ci);
uint32_t ci = strtoul(_ci, NULL, 10);
if (ci != endp->ci) {
LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
ENDPOINT_NUMBER(endp), endp->ci, _ci);
return -1;
}
@@ -367,6 +370,54 @@ static int parse_conn_mode(const char* msg, int *conn_mode)
return ret;
}
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
struct mgcp_port_range *range, int for_net)
{
int i;
if (range->mode == PORT_ALLOC_STATIC) {
end->local_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), range->base_port);
end->local_alloc = PORT_ALLOC_STATIC;
return 0;
}
/* attempt to find a port */
for (i = 0; i < 200; ++i) {
int rc;
if (range->last_port >= range->range_end)
range->last_port = range->range_start;
rc = for_net ?
mgcp_bind_net_rtp_port(endp, range->last_port) :
mgcp_bind_bts_rtp_port(endp, range->last_port);
range->last_port += 2;
if (rc == 0) {
end->local_alloc = PORT_ALLOC_DYNAMIC;
return 0;
}
}
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x net: %d\n",
ENDPOINT_NUMBER(endp), for_net);
return -1;
}
static int allocate_ports(struct mgcp_endpoint *endp)
{
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports, 1) != 0)
return -1;
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports, 0) != 0) {
mgcp_rtp_end_reset(&endp->net_end);
return -1;
}
return 0;
}
static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
{
struct mgcp_msg_ptr data_ptrs[6];
@@ -374,17 +425,18 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
int port;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
return create_response(500, "CRCX", trans_id);
if (endp->ci != CI_UNUSED) {
if (endp->allocated) {
if (cfg->force_realloc) {
LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
ENDPOINT_NUMBER(endp));
mgcp_free_endp(endp);
if (cfg->realloc_cb)
cfg->realloc_cb(cfg, ENDPOINT_NUMBER(endp));
} else {
LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
ENDPOINT_NUMBER(endp));
@@ -421,16 +473,13 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
MSG_TOKENIZE_END
/* initialize */
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
/* set to zero until we get the info */
memset(&endp->remote, 0, sizeof(endp->remote));
memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
/* bind to the port now */
port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
if (cfg->early_bind)
endp->rtp_port = port;
else if (mgcp_bind_rtp_port(endp, port) != 0)
if (allocate_ports(endp) != 0)
goto error2;
/* assign a local call identifier or fail */
@@ -438,7 +487,8 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
if (endp->ci == CI_UNUSED)
goto error2;
endp->bts_payload_type = cfg->audio_payload;
endp->allocated = 1;
endp->bts_end.payload_type = cfg->audio_payload;
/* policy CB */
if (cfg->policy_cb) {
@@ -459,10 +509,11 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
}
}
LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n",
ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
ENDPOINT_NUMBER(endp), endp->ci,
endp->net_end.local_port, endp->bts_end.local_port);
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port);
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
return create_response_with_sdp(endp, "CRCX", trans_id);
error:
@@ -472,6 +523,7 @@ error:
return create_response(error_code, "CRCX", trans_id);
error2:
mgcp_free_endp(endp);
LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
return create_response(error_code, "CRCX", trans_id);
}
@@ -536,9 +588,9 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
const char *param = (const char *)&msg->l3h[line_start];
if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
endp->net_rtp = htons(port);
endp->net_rtcp = htons(port + 1);
endp->net_payload_type = payload;
endp->net_end.rtp_port = htons(port);
endp->net_end.rtcp_port = htons(port + 1);
endp->net_end.payload_type = payload;
}
break;
}
@@ -547,7 +599,7 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
const char *param = (const char *)&msg->l3h[line_start];
if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
inet_aton(ipv4, &endp->remote);
inet_aton(ipv4, &endp->net_end.addr);
}
break;
}
@@ -580,10 +632,10 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
}
/* modify */
LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
if (silent)
goto out_silent;
@@ -616,7 +668,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
if (found != 0)
return create_response(error_code, "DLCX", trans_id);
if (endp->ci == CI_UNUSED) {
if (!endp->allocated) {
LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
return create_response(error_code, "DLCX", trans_id);
}
@@ -665,11 +717,11 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
}
/* free the connection */
LOGP(DMGCP, LOGL_NOTICE, "Deleted endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
mgcp_free_endp(endp);
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
if (silent)
goto out_silent;
@@ -709,11 +761,32 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000");
cfg->audio_payload = 97;
cfg->rtp_base_port = RTP_PORT_DEFAULT;
cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
return cfg;
}
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
{
if (end->local_alloc == PORT_ALLOC_DYNAMIC)
mgcp_free_rtp_port(end);
end->packets = 0;
memset(&end->addr, 0, sizeof(end->addr));
end->rtp_port = end->rtcp_port = end->local_port = 0;
end->payload_type = -1;
end->local_alloc = -1;
}
static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
{
mgcp_rtp_end_reset(end);
end->rtp.fd = -1;
end->rtcp.fd = -1;
}
int mgcp_endpoints_allocate(struct mgcp_config *cfg)
{
int i;
@@ -726,12 +799,10 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg)
return -1;
for (i = 0; i < cfg->number_endpoints; ++i) {
cfg->endpoints[i].local_rtp.fd = -1;
cfg->endpoints[i].local_rtcp.fd = -1;
cfg->endpoints[i].ci = CI_UNUSED;
cfg->endpoints[i].cfg = cfg;
cfg->endpoints[i].net_payload_type = -1;
cfg->endpoints[i].bts_payload_type = -1;
mgcp_rtp_end_init(&cfg->endpoints[i].net_end);
mgcp_rtp_end_init(&cfg->endpoints[i].bts_end);
}
return 0;
@@ -741,6 +812,7 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
{
LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
endp->ci = CI_UNUSED;
endp->allocated = 0;
if (endp->callid) {
talloc_free(endp->callid);
@@ -752,19 +824,14 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
endp->local_options = NULL;
}
if (!endp->cfg->early_bind) {
bsc_unregister_fd(&endp->local_rtp);
bsc_unregister_fd(&endp->local_rtcp);
}
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
endp->net_payload_type = endp->bts_payload_type = -1;
endp->in_bts = endp->in_remote = 0;
memset(&endp->remote, 0, sizeof(endp->remote));
memset(&endp->bts, 0, sizeof(endp->bts));
mgcp_rtp_end_reset(&endp->bts_end);
mgcp_rtp_end_reset(&endp->net_end);
memset(&endp->net_state, 0, sizeof(endp->net_state));
memset(&endp->bts_state, 0, sizeof(endp->bts_state));
endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
endp->allow_patch = 0;
memset(&endp->taps, 0, sizeof(endp->taps));
}

View File

@@ -55,8 +55,19 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC)
vty_out(vty, " rtp bts-base %u%s", g_cfg->bts_ports.base_port, VTY_NEWLINE);
else
vty_out(vty, " rtp bts-range %u %u%s",
g_cfg->bts_ports.range_start, g_cfg->bts_ports.range_end, VTY_NEWLINE);
if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC)
vty_out(vty, " rtp net-base %u%s", g_cfg->net_ports.base_port, VTY_NEWLINE);
else
vty_out(vty, " rtp net-range %u %u%s",
g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
if (g_cfg->audio_payload != -1)
vty_out(vty, " sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
@@ -64,10 +75,6 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
vty_out(vty, " loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE);
vty_out(vty, " number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
if (g_cfg->forward_ip)
vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
if (g_cfg->forward_port != 0)
vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
if (g_cfg->call_agent_addr)
vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
@@ -84,10 +91,11 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u/%u remote: %u/%u%s",
i, endp->ci,
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
inet_ntoa(endp->bts), endp->in_bts, endp->bts_state.lost_no,
endp->in_remote, endp->net_state.lost_no,
ntohs(endp->net_end.rtp_port), ntohs(endp->net_end.rtcp_port),
ntohs(endp->bts_end.rtp_port), ntohs(endp->bts_end.rtcp_port),
inet_ntoa(endp->bts_end.addr),
endp->bts_end.packets, endp->bts_state.lost_no,
endp->net_end.packets, endp->net_state.lost_no,
VTY_NEWLINE);
}
@@ -152,21 +160,61 @@ DEFUN(cfg_mgcp_bind_early,
"bind early (0|1)",
"Bind all RTP ports early")
{
unsigned int bind = atoi(argv[0]);
g_cfg->early_bind = bind == 1;
return CMD_SUCCESS;
vty_out(vty, "bind early is deprecated, remove it from the config.\n");
return CMD_WARNING;
}
DEFUN(cfg_mgcp_rtp_base_port,
cfg_mgcp_rtp_base_port_cmd,
"rtp base <0-65534>",
DEFUN(cfg_mgcp_rtp_bts_base_port,
cfg_mgcp_rtp_bts_base_port_cmd,
"rtp bts-base <0-65534>",
"Base port to use")
{
unsigned int port = atoi(argv[0]);
g_cfg->rtp_base_port = port;
g_cfg->bts_ports.mode = PORT_ALLOC_STATIC;
g_cfg->bts_ports.base_port = port;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_bts_range,
cfg_mgcp_rtp_bts_range_cmd,
"rtp bts-range <0-65534> <0-65534>",
"Range of ports to allocate for endpoints\n"
"Start of the range of ports\n" "End of the range of ports\n")
{
g_cfg->bts_ports.mode = PORT_ALLOC_DYNAMIC;
g_cfg->bts_ports.range_start = atoi(argv[0]);
g_cfg->bts_ports.range_end = atoi(argv[1]);
g_cfg->bts_ports.last_port = g_cfg->bts_ports.range_start;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_net_range,
cfg_mgcp_rtp_net_range_cmd,
"rtp net-range <0-65534> <0-65534>",
"Range of ports to allocate for endpoints\n"
"Start of the range of ports\n" "End of the range of ports\n")
{
g_cfg->net_ports.mode = PORT_ALLOC_DYNAMIC;
g_cfg->net_ports.range_start = atoi(argv[0]);
g_cfg->net_ports.range_end = atoi(argv[1]);
g_cfg->net_ports.last_port = g_cfg->net_ports.range_start;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_net_base_port,
cfg_mgcp_rtp_net_base_port_cmd,
"rtp net-base <0-65534>",
"Base port to use for network port\n" "Port\n")
{
unsigned int port = atoi(argv[0]);
g_cfg->net_ports.mode = PORT_ALLOC_STATIC;
g_cfg->net_ports.base_port = port;
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgcp_rtp_bts_base_port, cfg_mgcp_rtp_base_port_cmd,
"rtp base <0-65534>", "Base port to use")
DEFUN(cfg_mgcp_rtp_ip_dscp,
cfg_mgcp_rtp_ip_dscp_cmd,
"rtp ip-dscp <0-255>",
@@ -222,26 +270,6 @@ DEFUN(cfg_mgcp_number_endp,
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_forward_ip,
cfg_mgcp_forward_ip_cmd,
"forward audio ip A.B.C.D",
"Forward packets from and to the IP. This disables most of the MGCP feature.")
{
if (g_cfg->forward_ip)
talloc_free(g_cfg->forward_ip);
g_cfg->forward_ip = talloc_strdup(g_cfg, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_forward_port,
cfg_mgcp_forward_port_cmd,
"forward audio port <1-15000>",
"Forward packets from and to the port. This disables most of the MGCP feature.")
{
g_cfg->forward_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_agent_addr,
cfg_mgcp_agent_addr_cmd,
"call agent ip IP",
@@ -276,14 +304,61 @@ DEFUN(loop_endp,
endp->conn_mode = MGCP_CONN_LOOPBACK;
else
endp->conn_mode = endp->orig_mode;
endp->allow_patch = 1;
return CMD_SUCCESS;
}
DEFUN(tap_call,
tap_call_cmd,
"tap-call ENDPOINT (bts-in|bts-out|net-in|net-out) A.B.C.D <0-65534>",
"Forward data on endpoint to a different system\n"
"The endpoint in hex\n"
"Forward the data coming from the bts\n"
"Forward the data coming from the bts leaving to the network\n"
"Forward the data coming from the net\n"
"Forward the data coming from the net leaving to the bts\n"
"destination IP of the data\n" "destination port\n")
{
struct mgcp_rtp_tap *tap;
struct mgcp_endpoint *endp;
int port = 0;
int endp_no = strtoul(argv[0], NULL, 16);
if (endp_no < 1 || endp_no >= g_cfg->number_endpoints) {
vty_out(vty, "Endpoint number %s/%d is invalid.%s",
argv[0], endp_no, VTY_NEWLINE);
return CMD_WARNING;
}
endp = &g_cfg->endpoints[endp_no];
if (strcmp(argv[1], "bts-in") == 0) {
port = MGCP_TAP_BTS_IN;
} else if (strcmp(argv[1], "bts-out") == 0) {
port = MGCP_TAP_BTS_OUT;
} else if (strcmp(argv[1], "net-in") == 0) {
port = MGCP_TAP_NET_IN;
} else if (strcmp(argv[1], "net-out") == 0) {
port = MGCP_TAP_NET_OUT;
} else {
vty_out(vty, "Unknown mode... tricked vty?%s", VTY_NEWLINE);
return CMD_WARNING;
}
tap = &endp->taps[port];
memset(&tap->forward, 0, sizeof(tap->forward));
inet_aton(argv[2], &tap->forward.sin_addr);
tap->forward.sin_port = htons(atoi(argv[3]));
tap->enabled = 1;
return CMD_SUCCESS;
}
int mgcp_vty_init(void)
{
install_element(VIEW_NODE, &show_mgcp_cmd);
install_element(ENABLE_NODE, &loop_endp_cmd);
install_element(ENABLE_NODE, &tap_call_cmd);
install_element(CONFIG_NODE, &cfg_mgcp_cmd);
install_node(&mgcp_node, config_write_mgcp);
@@ -295,14 +370,16 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_base_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_base_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
return 0;
}
@@ -332,51 +409,32 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
return -1;
}
/*
* This application supports two modes.
* 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
* 2.) plain forwarding of RTP packets on the endpoints.
* both modes are mutual exclusive
*/
if (g_cfg->forward_ip) {
int port = g_cfg->rtp_base_port;
if (g_cfg->forward_port != 0)
port = g_cfg->forward_port;
if (!g_cfg->early_bind) {
LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n");
return -1;
}
/*
* Store the forward IP and assign a ci. For early bind
* the sockets will be created after this.
*/
for (i = 1; i < g_cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
inet_aton(g_cfg->forward_ip, &endp->remote);
endp->ci = CI_UNUSED + 23;
endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
}
LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n");
}
/* early bind */
if (g_cfg->early_bind) {
for (i = 1; i < g_cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
int rtp_port;
for (i = 1; i < g_cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
int rtp_port;
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), g_cfg->rtp_base_port);
if (mgcp_bind_rtp_port(endp, rtp_port) != 0) {
if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC) {
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
g_cfg->bts_ports.base_port);
if (mgcp_bind_bts_rtp_port(endp, rtp_port) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
endp->bts_end.local_alloc = PORT_ALLOC_STATIC;
}
if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC) {
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
g_cfg->net_ports.base_port);
if (mgcp_bind_net_rtp_port(endp, rtp_port) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
endp->net_end.local_alloc = PORT_ALLOC_STATIC;
}
}
return !!g_cfg->forward_ip;
return 0;
}

View File

@@ -19,8 +19,8 @@
*
*/
#include <openbsc/bsc_msc_grace.h>
#include <openbsc/bsc_msc_rf.h>
#include <openbsc/osmo_bsc_grace.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/gsm_04_80.h>
#include <openbsc/signal.h>
@@ -58,7 +58,7 @@ static int handle_grace(struct gsm_network *network)
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
if (!network->ussd_grace_txt)
if (!network->mid_call_txt)
return 0;
llist_for_each_entry(bts, &network->bts_list, list) {
@@ -67,7 +67,7 @@ static int handle_grace(struct gsm_network *network)
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; ++lchan_nr) {
handle_sub(&ts->lchan[lchan_nr],
network->ussd_grace_txt);
network->mid_call_txt);
}
}
}

View File

@@ -21,10 +21,11 @@
*
*/
#include <openbsc/bsc_msc_rf.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/signal.h>
#include <openbsc/ipaccess.h>
#include <osmocore/talloc.h>
#include <osmocore/protocol/gsm_12_21.h>
@@ -38,7 +39,8 @@
#define RF_CMD_QUERY '?'
#define RF_CMD_OFF '0'
#define RF_CMD_ON '1'
#define RF_CMD_GRACE 'g'
#define RF_CMD_D_OFF 'd'
#define RF_CMD_ON_G 'g'
static int lock_each_trx(struct gsm_network *net, int lock)
{
@@ -54,25 +56,9 @@ static int lock_each_trx(struct gsm_network *net, int lock)
return 0;
}
/*
* Send a '1' when one TRX is online, otherwise send 0
*/
static void handle_query(struct bsc_msc_rf_conn *conn)
static void send_resp(struct osmo_bsc_rf_conn *conn, char send)
{
struct msgb *msg;
struct gsm_bts *bts;
char send = RF_CMD_OFF;
llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->nm_state.availability == NM_AVSTATE_OK &&
trx->nm_state.operational != NM_STATE_LOCKED) {
send = RF_CMD_ON;
break;
}
}
}
msg = msgb_alloc(10, "RF Query");
if (!msg) {
@@ -92,18 +78,125 @@ static void handle_query(struct bsc_msc_rf_conn *conn)
return;
}
static void send_signal(struct bsc_msc_rf_conn *conn, int val)
/*
* Send a
* 'g' when we are in grace mode
* '1' when one TRX is online,
* '0' otherwise
*/
static void handle_query(struct osmo_bsc_rf_conn *conn)
{
struct gsm_bts *bts;
char send = RF_CMD_OFF;
if (conn->rf->policy == S_RF_GRACE)
return send_resp(conn, RF_CMD_ON_G);
llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->nm_state.availability == NM_AVSTATE_OK &&
trx->nm_state.operational != NM_STATE_LOCKED) {
send = RF_CMD_ON;
break;
}
}
}
send_resp(conn, send);
}
static void rf_check_cb(void *_data)
{
struct gsm_bts *bts;
struct osmo_bsc_rf *rf = _data;
llist_for_each_entry(bts, &rf->gsm_network->bts_list, list) {
struct gsm_bts_trx *trx;
/* don't bother to check a booting or missing BTS */
if (!bts->oml_link || !is_ipaccess_bts(bts))
continue;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->nm_state.availability != NM_AVSTATE_OK ||
trx->nm_state.operational != NM_OPSTATE_ENABLED ||
trx->nm_state.administrative != NM_STATE_UNLOCKED) {
LOGP(DNM, LOGL_ERROR, "RF activation failed. Starting again.\n");
ipaccess_drop_oml(bts);
break;
}
}
}
}
static void send_signal(struct osmo_bsc_rf *rf, int val)
{
struct rf_signal_data sig;
sig.net = conn->rf->gsm_network;
sig.net = rf->gsm_network;
conn->rf->policy = val;
rf->policy = val;
dispatch_signal(SS_RF, val, &sig);
}
static int switch_rf_off(struct osmo_bsc_rf *rf)
{
lock_each_trx(rf->gsm_network, 1);
send_signal(rf, S_RF_OFF);
return 0;
}
static void grace_timeout(void *_data)
{
struct osmo_bsc_rf *rf = (struct osmo_bsc_rf *) _data;
LOGP(DINP, LOGL_NOTICE, "Grace timeout. Disabling the TRX.\n");
switch_rf_off(rf);
}
static int enter_grace(struct osmo_bsc_rf *rf)
{
rf->grace_timeout.cb = grace_timeout;
rf->grace_timeout.data = rf;
bsc_schedule_timer(&rf->grace_timeout, rf->gsm_network->mid_call_timeout, 0);
LOGP(DINP, LOGL_NOTICE, "Going to switch RF off in %d seconds.\n",
rf->gsm_network->mid_call_timeout);
send_signal(rf, S_RF_GRACE);
return 0;
}
static void rf_delay_cmd_cb(void *data)
{
struct osmo_bsc_rf *rf = data;
switch (rf->last_request) {
case RF_CMD_D_OFF:
rf->last_state_command = "RF Direct Off";
bsc_del_timer(&rf->rf_check);
bsc_del_timer(&rf->grace_timeout);
switch_rf_off(rf);
break;
case RF_CMD_ON:
rf->last_state_command = "RF Direct On";
bsc_del_timer(&rf->grace_timeout);
lock_each_trx(rf->gsm_network, 0);
send_signal(rf, S_RF_ON);
bsc_schedule_timer(&rf->rf_check, 3, 0);
break;
case RF_CMD_OFF:
rf->last_state_command = "RF Scheduled Off";
bsc_del_timer(&rf->rf_check);
enter_grace(rf);
break;
}
}
static int rf_read_cmd(struct bsc_fd *fd)
{
struct bsc_msc_rf_conn *conn = fd->data;
struct osmo_bsc_rf_conn *conn = fd->data;
char buf[1];
int rc;
@@ -121,18 +214,15 @@ static int rf_read_cmd(struct bsc_fd *fd)
case RF_CMD_QUERY:
handle_query(conn);
break;
case RF_CMD_OFF:
lock_each_trx(conn->rf->gsm_network, 1);
send_signal(conn, S_RF_OFF);
break;
case RF_CMD_D_OFF:
case RF_CMD_ON:
lock_each_trx(conn->rf->gsm_network, 0);
send_signal(conn, S_RF_ON);
break;
case RF_CMD_GRACE:
send_signal(conn, S_RF_GRACE);
case RF_CMD_OFF:
conn->rf->last_request = buf[0];
if (!bsc_timer_pending(&conn->rf->delay_cmd))
bsc_schedule_timer(&conn->rf->delay_cmd, 1, 0);
break;
default:
conn->rf->last_state_command = "Unknown command";
LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
break;
}
@@ -155,8 +245,8 @@ static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
{
struct bsc_msc_rf_conn *conn;
struct bsc_msc_rf *rf = bfd->data;
struct osmo_bsc_rf_conn *conn;
struct osmo_bsc_rf *rf = bfd->data;
struct sockaddr_un addr;
socklen_t len = sizeof(addr);
int fd;
@@ -168,7 +258,7 @@ static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
return -1;
}
conn = talloc_zero(rf, struct bsc_msc_rf_conn);
conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
if (!conn) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
close(fd);
@@ -192,17 +282,17 @@ static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
return 0;
}
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net)
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
{
unsigned int namelen;
struct sockaddr_un local;
struct bsc_fd *bfd;
struct bsc_msc_rf *rf;
struct osmo_bsc_rf *rf;
int rc;
rf = talloc_zero(NULL, struct bsc_msc_rf);
rf = talloc_zero(NULL, struct osmo_bsc_rf);
if (!rf) {
LOGP(DINP, LOGL_ERROR, "Failed to create bsc_msc_rf.\n");
LOGP(DINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
return NULL;
}
@@ -260,6 +350,15 @@ struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net)
rf->gsm_network = net;
rf->policy = S_RF_ON;
rf->last_state_command = "";
/* check the rf state */
rf->rf_check.data = rf;
rf->rf_check.cb = rf_check_cb;
/* delay cmd handling */
rf->delay_cmd.data = rf;
rf->delay_cmd.cb = rf_delay_cmd_cb;
return rf;
}

File diff suppressed because it is too large Load Diff

View File

@@ -45,8 +45,11 @@ static int send_own_number(const struct msgb *msg, const struct ussd_request *re
int handle_rcv_ussd(struct msgb *msg)
{
struct ussd_request req;
struct gsm48_hdr *gh;
gsm0480_decode_ussd_request(msg, &req);
memset(&req, 0, sizeof(req));
gh = msgb_l3(msg);
gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req);
if (req.text[0] == 0xFF) /* Release-Complete */
return 0;

View File

@@ -1949,6 +1949,11 @@ enum node_type vty_go_parent(struct vty *vty)
subscr_put(vty->index);
vty->index = NULL;
break;
case OML_NODE:
vty->node = ENABLE_NODE;
talloc_free(vty->index);
vty->index = NULL;
break;
default:
vty->node = CONFIG_NODE;
}
@@ -2365,7 +2370,12 @@ DEFUN(config_exit,
case MGCP_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
case OML_NODE:
vty->node = ENABLE_NODE;
talloc_free(vty->index);
vty->index = NULL;
break;
default:
break;
}

View File

@@ -42,6 +42,7 @@
#include <openbsc/vty.h>
#include <openbsc/ipaccess.h>
#include <openbsc/paging.h>
#include <openbsc/osmo_bsc_rf.h>
static struct gsm_network *gsmnet;
@@ -164,6 +165,10 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
vty_out(vty, "hr: %d ver: %d, ",
net->audio_support[i]->hr, net->audio_support[i]->ver);
vty_out(vty, "%s", VTY_NEWLINE);
/* show rf */
vty_out(vty, " Last RF Command: %s%s",
net->rf->last_state_command, VTY_NEWLINE);
}
DEFUN(show_net, show_net_cmd, "show network",
@@ -227,11 +232,15 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " Paging: %u pending requests, %u free slots%s",
paging_pending_requests_nr(bts),
bts->paging.available_slots, VTY_NEWLINE);
if (!is_ipaccess_bts(bts)) {
if (is_ipaccess_bts(bts)) {
vty_out(vty, " OML Link state: %s.%s",
bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE);
} else {
vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
e1isl_dump_vty(vty, bts->oml_link);
}
/* FIXME: oml_link, chan_desc */
/* FIXME: chan_desc */
memset(&pl, 0, sizeof(pl));
bts_chan_load(&pl, bts);
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
@@ -528,8 +537,11 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " msc ip-dscp %d%s", gsmnet->msc_ip_dscp, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", gsmnet->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout pong %d%s", gsmnet->pong_timeout, VTY_NEWLINE);
if (gsmnet->ussd_grace_txt)
vty_out(vty, " bsc-grace-text %s%s", gsmnet->ussd_grace_txt, VTY_NEWLINE);
if (gsmnet->mid_call_txt)
vty_out(vty, " mid-call-text %s%s", gsmnet->mid_call_txt, VTY_NEWLINE);
vty_out(vty, " mid-call-timeout %d%s", gsmnet->mid_call_timeout, VTY_NEWLINE);
if (gsmnet->ussd_welcome_txt)
vty_out(vty, " bsc-welcome-text %s%s", gsmnet->ussd_welcome_txt, VTY_NEWLINE);
return CMD_SUCCESS;
@@ -1446,18 +1458,43 @@ DEFUN(cfg_net_pong_time,
return CMD_SUCCESS;
}
DEFUN(cfg_net_grace_ussd,
cfg_net_grace_ussd_cmd,
"bsc-grace-text .TEXT",
DEFUN(cfg_net_mid_call_text,
cfg_net_mid_call_text_cmd,
"mid-call-text .TEXT",
"Set the USSD notifcation to be send.\n" "Text to be sent\n")
{
char *data = argv_concat(argv, argc, 1);
char *data = argv_concat(argv, argc, 0);
if (!data)
return CMD_WARNING;
if (gsmnet->ussd_grace_txt)
talloc_free(gsmnet->ussd_grace_txt);
gsmnet->ussd_grace_txt = talloc_strdup(gsmnet, data);
if (gsmnet->mid_call_txt)
talloc_free(gsmnet->mid_call_txt);
gsmnet->mid_call_txt = talloc_strdup(gsmnet, data);
talloc_free(data);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mid_call_timeout,
cfg_net_mid_call_timeout_cmd,
"mid-call-timeout NR",
"Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
{
gsmnet->mid_call_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_welcome_ussd,
cfg_net_welcome_ussd_cmd,
"bsc-welcome-text .TEXT",
"Set the USSD notification to be sent.\n" "Text to be sent\n")
{
char *data = argv_concat(argv, argc, 0);
if (!data)
return CMD_WARNING;
if (gsmnet->ussd_welcome_txt)
talloc_free(gsmnet->ussd_welcome_txt);
gsmnet->ussd_welcome_txt = talloc_strdup(gsmnet, data);
talloc_free(data);
return CMD_SUCCESS;
}
@@ -2284,7 +2321,9 @@ int bsc_vty_init(struct gsm_network *net)
install_element(GSMNET_NODE, &cfg_net_msc_prio_cmd);
install_element(GSMNET_NODE, &cfg_net_ping_time_cmd);
install_element(GSMNET_NODE, &cfg_net_pong_time_cmd);
install_element(GSMNET_NODE, &cfg_net_grace_ussd_cmd);
install_element(GSMNET_NODE, &cfg_net_mid_call_text_cmd);
install_element(GSMNET_NODE, &cfg_net_mid_call_timeout_cmd);
install_element(GSMNET_NODE, &cfg_net_welcome_ussd_cmd);
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);
@@ -2338,6 +2377,8 @@ int bsc_vty_init(struct gsm_network *net)
install_element(TS_NODE, &cfg_ts_pchan_cmd);
install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
abis_nm_vty_init();
bsc_vty_init_extra(net);
return 0;

View File

@@ -30,7 +30,7 @@
#include <openbsc/bsc_msc.h>
#include <openbsc/vty.h>
#include <sccp/sccp.h>
#include <osmocom/sccp/sccp.h>
static struct gsm_network *gsmnet = NULL;

View File

@@ -1 +1 @@
SUBDIRS = debug gsm0408 db channel sccp
SUBDIRS = debug gsm0408 db channel

View File

@@ -1,8 +0,0 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
noinst_PROGRAMS = sccp_test
sccp_test_SOURCES = sccp_test.c
sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS)

View File

@@ -1,851 +0,0 @@
/*
* SCCP testing code
*
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 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 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <arpa/inet.h>
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <osmocore/msgb.h>
#include <sccp/sccp.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
/* BSC -> MSC */
static const u_int8_t bssmap_reset[] = {
0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
0x01, 0x20,
};
/* MSC -> BSC reset ack */
static const u_int8_t bssmap_reset_ack[] = {
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
0x00, 0x01, 0x31,
};
/* MSC -> BSC paging, connection less */
static const u_int8_t bssmap_paging[] = {
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10,
0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06,
};
/* MSC -> BSC paging, UDT without PC */
static const u_int8_t bssmap_udt[] = {
0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08,
0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97,
0x61, 0x1a, 0x01, 0x06,
};
/* BSC -> MSC connection open */
static const u_int8_t bssmap_cr[] = {
0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02,
0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05,
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3,
0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33,
0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01,
0x31, 0x97, 0x61, 0x00
};
/* MSC -> BSC connection confirm */
static const u_int8_t bssmap_cc[] = {
0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
};
/* MSC -> BSC DTAP
*
* we fake a bit and make it BSC -> MSC... so the
* payload does not make any sense..
*/
static const u_int8_t bssmap_dtap[] = {
0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c,
0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13,
0x45, 0xf4,
};
/* MSC -> BSC clear command */
static const u_int8_t bssmap_clear[] = {
0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20,
0x04, 0x01, 0x09,
};
/* MSC -> BSC released */
static const u_int8_t bssmap_released[] = {
0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f,
0x02, 0x23, 0x42, 0x00,
};
/* BSC -> MSC released */
static const u_int8_t bssmap_release_complete[] = {
0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03
};
struct test_data {
int length;
const u_int8_t *data;
int payload_start;
int payload_length;
u_int8_t first_byte;
/* in case it should trigger a sccp response */
int write;
const u_int8_t *response;
int response_length;
};
static const struct test_data test_data[] = {
{
.length = ARRAY_SIZE(bssmap_reset),
.data = &bssmap_reset[0],
.payload_start = 12,
.payload_length = ARRAY_SIZE(bssmap_reset) - 12,
.first_byte = 0x0,
},
{
.length = ARRAY_SIZE(bssmap_reset_ack),
.data = &bssmap_reset_ack[0],
.payload_start = 16,
.payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16,
.first_byte = 0x0,
},
{
.length = ARRAY_SIZE(bssmap_paging),
.data = &bssmap_paging[0],
.payload_start = 16,
.payload_length = ARRAY_SIZE(bssmap_paging) - 16,
.first_byte = 0x0,
},
{
.length = ARRAY_SIZE(bssmap_cr),
.data = &bssmap_cr[0],
.payload_start = 12,
/* 0x00 is end of optional data, subtract this byte */
.payload_length = 31,
.first_byte = 0x0,
/* the connection request should trigger a connection confirm */
.write = 1,
.response = &bssmap_cc[0],
.response_length= ARRAY_SIZE(bssmap_cc),
},
{
.length = ARRAY_SIZE(bssmap_dtap),
.data = &bssmap_dtap[0],
.payload_start = 7,
.payload_length = 15,
.first_byte = 0x01,
},
{
.length = ARRAY_SIZE(bssmap_clear),
.data = &bssmap_clear[0],
.payload_start = 7,
.payload_length = 6,
.first_byte = 0x00,
},
{
.length = ARRAY_SIZE(bssmap_released),
.data = &bssmap_released[0],
.payload_length = 2,
.payload_start = 11,
.first_byte = 0x23,
.write = 1,
.response = &bssmap_release_complete[0],
.response_length= ARRAY_SIZE(bssmap_release_complete),
},
};
/* we will send UDTs and verify they look like this */
static const struct test_data send_data[] = {
{
.length = ARRAY_SIZE(bssmap_udt),
.data = &bssmap_udt[0],
.payload_start = 12,
.payload_length = ARRAY_SIZE(bssmap_udt) - 12,
.first_byte = 0x0,
},
{
.length = ARRAY_SIZE(bssmap_reset),
.data = &bssmap_reset[0],
.payload_start = 12,
.payload_length = ARRAY_SIZE(bssmap_reset) - 12,
.first_byte = 0x0,
},
};
struct connection_test {
/* should the connection be refused? */
int refuse;
int with_data;
/* on which side to close the connection? */
int close_side;
int close_cause;
};
/* sccp connection handling we want to test */
static const struct connection_test connection_tests[] = {
{
.refuse = 1,
},
{
.refuse = 1,
.with_data = 1,
},
{
.refuse = 0,
.close_side = 0,
.close_cause = 5,
},
{
.refuse = 0,
.close_side = 0,
.close_cause = 5,
.with_data = 1,
},
{
.refuse = 0,
.close_side = 1,
.close_cause = 5,
},
{
.refuse = 0,
.close_side = 1,
.close_cause = 5,
.with_data = 1,
},
};
struct sccp_parse_header_result {
/* results */
int msg_type;
int wanted_len;
int src_ssn;
int dst_ssn;
int has_src_ref, has_dst_ref;
struct sccp_source_reference src_ref;
struct sccp_source_reference dst_ref;
/* the input */
const u_int8_t *input;
int input_len;
};
static const u_int8_t it_test[] = {
0x10, 0x01, 0x07,
0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 };
static const u_int8_t proto_err[] = {
0x0f, 0x0c, 0x04, 0x00, 0x00,
};
static const struct sccp_parse_header_result parse_result[] = {
{
.msg_type = SCCP_MSG_TYPE_IT,
.wanted_len = 0,
.src_ssn = -1,
.dst_ssn = -1,
.has_src_ref = 1,
.has_dst_ref = 1,
.src_ref = {
.octet1 = 0x01,
.octet2 = 0x04,
.octet3 = 0x00
},
.dst_ref = {
.octet1 = 0x01,
.octet2 = 0x07,
.octet3 = 0x94,
},
.input = it_test,
.input_len = sizeof(it_test),
},
{
.msg_type = SCCP_MSG_TYPE_ERR,
.wanted_len = 0,
.src_ssn = -1,
.dst_ssn = -1,
.has_src_ref = 0,
.has_dst_ref = 1,
.dst_ref = {
.octet1 = 0x0c,
.octet2 = 0x04,
.octet3 = 0x00,
},
.input = proto_err,
.input_len = sizeof(proto_err),
},
};
/* testing procedure:
* - we will use sccp_write and see what will be set in the
* outgoing callback
* - we will call sccp_system_incoming and see which calls
* are made. And then compare it to the ones we expect. We
* want the payload to arrive, or callbacks to be called.
* - we will use sccp_connection_socket and sccp_connection_write
* and verify state handling of connections
*/
static int current_test;
/*
* test state...
*/
static int called = 0;
static int matched = 0;
static int write_called = 0;
#define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args)
/*
* writing these packets and expecting a result
*/
int sccp_read_cb(struct msgb *data, unsigned len, void *context)
{
u_int16_t payload_length = test_data[current_test].payload_length;
const u_int8_t *got, *wanted;
int i;
called = 1;
if (msgb_l3len(data) < len) {
/* this should never be reached */
FAIL("Something horrible happened.. invalid packet..\n");
exit(-1);
}
if (len == 0 || len != payload_length) {
FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length);
return -1;
}
if (data->l3h[0] != test_data[current_test].first_byte) {
FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n",
data->l3h[0], test_data[current_test].first_byte);
return -1;
}
got = &data->l3h[0];
wanted = test_data[current_test].data + test_data[current_test].payload_start;
for (i = 0; i < len; ++i) {
if (got[i] != wanted[i]) {
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
got[i], wanted[i], i);
return -1;
}
}
matched = 1;
return 0;
}
void sccp_write_cb(struct msgb *data, void *ctx)
{
int i = 0;
const u_int8_t *got, *wanted;
if (test_data[current_test].response == NULL) {
FAIL("Didn't expect write callback\n");
goto exit;
} else if (test_data[current_test].response_length != msgb_l2len(data)) {
FAIL("Size does not match. Got: %d Wanted: %d\n",
msgb_l2len(data), test_data[current_test].response_length);
}
got = &data->l2h[0];
wanted = test_data[current_test].response;
for (i = 0; i < msgb_l2len(data); ++i) {
if (got[i] != wanted[i]) {
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
got[i], wanted[i], i);
goto exit;
}
}
write_called = 1;
exit:
msgb_free(data);
}
void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len)
{
sccp_read_cb(msgb, len, connection->data_ctx);
}
void sccp_c_state(struct sccp_connection *connection, int old_state)
{
if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE)
sccp_connection_free(connection);
}
int sccp_accept_cb(struct sccp_connection *connection, void *user_data)
{
called = 1;
unsigned int ref = 0;
ref |= connection->destination_local_reference.octet1 << 24;
ref |= connection->destination_local_reference.octet2 << 16;
ref |= connection->destination_local_reference.octet3 << 8;
ref = ntohl(ref);
connection->data_cb = sccp_c_read;
connection->state_cb = sccp_c_state;
/* accept this */
return 0;
}
static void sccp_udt_write_cb(struct msgb *data, void *context)
{
const u_int8_t *got, *wanted;
int i;
write_called = 1;
if (send_data[current_test].length != msgb_l2len(data)) {
FAIL("Size does not match. Got: %d Wanted: %d\n",
msgb_l2len(data), send_data[current_test].length);
goto exit;
}
got = &data->l2h[0];
wanted = send_data[current_test].data;
for (i = 0; i < msgb_l2len(data); ++i) {
if (got[i] != wanted[i]) {
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
got[i], wanted[i], i);
goto exit;
}
}
matched = 1;
exit:
msgb_free(data);
}
static void test_sccp_system(void)
{
sccp_system_init(sccp_write_cb, NULL);
sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
unsigned int length = test_data[current_test].length;
struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
msg->l2h = msgb_put(msg, length);
memcpy(msg->l2h, test_data[current_test].data, length);
called = matched = write_called = 0;
printf("Testing packet: %d\n", current_test);
sccp_system_incoming(msg);
if (!called || !matched || (test_data[current_test].write != write_called))
FAIL("current test: %d called: %d matched: %d write: %d\n",
current_test, called, matched, write_called);
msgb_free(msg);
}
}
/* test sending of udt */
static void test_sccp_send_udt(void)
{
sccp_system_init(sccp_udt_write_cb, NULL);
sccp_set_read(NULL, NULL, NULL);
sccp_connection_set_incoming(NULL, NULL, NULL);
for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) {
const struct test_data *test = &send_data[current_test];
struct msgb *msg = msgb_alloc(test->payload_length, __func__);
msg->l3h = msgb_put(msg, test->payload_length);
memcpy(msg->l3h, test->data + test->payload_start, test->payload_length);
matched = write_called = 0;
printf("Testing packet: %d\n", current_test);
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
if (!matched || !write_called)
FAIL("current test: %d matched: %d write: %d\n",
current_test, matched, write_called);
msgb_free(msg);
}
}
/* send udt from one end to another */
static unsigned int test_value = 0x2442;
static int sccp_udt_read(struct msgb *data, unsigned int len, void *context)
{
unsigned int *val;
if (len != 4) {
FAIL("Wrong size: %d\n", msgb_l3len(data));
return -1;
}
val = (unsigned int*)data->l3h;
matched = test_value == *val;
return 0;
}
static void sccp_write_loop(struct msgb *data, void *context)
{
/* send it back to us */
sccp_system_incoming(data);
msgb_free(data);
}
static void test_sccp_udt_communication(void)
{
struct msgb *data;
unsigned int *val;
sccp_system_init(sccp_write_loop, NULL);
sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL);
sccp_connection_set_incoming(NULL, NULL, NULL);
data = msgb_alloc(4, "test data");
data->l3h = &data->data[0];
val = (unsigned int *)msgb_put(data, 4);
*val = test_value;
matched = 0;
sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
if (!matched)
FAIL("Talking with us didn't work\n");
msgb_free(data);
}
/* connection testing... open, send, close */
static const struct connection_test *current_con_test;
static struct sccp_connection *outgoing_con;
static struct sccp_connection *incoming_con;
static int outgoing_data, incoming_data, incoming_state, outgoing_state;
static struct msgb *test_data1, *test_data2, *test_data3;
static void sccp_conn_in_state(struct sccp_connection *conn, int old_state)
{
printf("\tincome: %d -> %d\n", old_state, conn->connection_state);
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
if (conn == incoming_con) {
sccp_connection_free(conn);
incoming_con = NULL;
}
}
}
static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
{
/* compare the data */
++incoming_data;
printf("\tincoming data: %d\n", len);
/* compare the data */
if (len != 4) {
FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
return;
}
if (incoming_data == 1) {
if (memcmp(msg->l3h, test_data1->l3h, len) != 0) {
FAIL("Comparing the data failed: %d\n", incoming_data);
incoming_state = 0;
printf("Got: %s\n", hexdump(msg->l3h, len));
printf("Wanted: %s\n", hexdump(test_data1->l3h, len));
}
} else if (incoming_data == 2) {
if (memcmp(msg->l3h, test_data2->l3h, len) != 0) {
FAIL("Comparing the data failed: %d\n", incoming_data);
incoming_state = 0;
printf("Got: %s\n", hexdump(msg->l3h, len));
printf("Wanted: %s\n", hexdump(test_data2->l3h, len));
}
}
/* sending out data */
if (incoming_data == 2) {
printf("\tReturning data3\n");
sccp_connection_write(conn, test_data3);
}
}
static int sccp_conn_accept(struct sccp_connection *conn, void *ctx)
{
printf("\taccept: %p\n", conn);
conn->state_cb = sccp_conn_in_state;
conn->data_cb = sccp_conn_in_data;
if (current_con_test->refuse)
return -1;
incoming_con = conn;
return 0;
}
/* callbacks for the outgoing side */
static void sccp_conn_out_state(struct sccp_connection *conn, int old_state)
{
printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state);
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
if (conn == outgoing_con) {
sccp_connection_free(conn);
outgoing_con = NULL;
}
}
}
static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
{
++outgoing_data;
printf("\toutgoing data: %p %d\n", conn, len);
if (len != 4)
FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
if (outgoing_data == 1) {
if (memcmp(msg->l3h, test_data3->l3h, len) != 0) {
FAIL("Comparing the data failed\n");
outgoing_state = 0;
}
}
}
static void do_test_sccp_connection(const struct connection_test *test)
{
int ret;
current_con_test = test;
outgoing_con = incoming_con = 0;
outgoing_con = sccp_connection_socket();
if (!outgoing_con) {
FAIL("Connection is NULL\n");
return;
}
outgoing_con->state_cb = sccp_conn_out_state;
outgoing_con->data_cb = sccp_conn_out_data;
outgoing_data = incoming_data = 0;
incoming_state = outgoing_state = 1;
/* start testing */
if (test->with_data) {
if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0)
FAIL("Binding failed\n");
} else {
++incoming_data;
if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0)
FAIL("Binding failed\n");
}
if (test->refuse) {
if (outgoing_con)
FAIL("Outgoing connection should have been refused.\n");
} else {
if (!incoming_con)
FAIL("Creating incoming didn't work.\n");
printf("\tWriting test data2\n");
sccp_connection_write(outgoing_con, test_data2);
sccp_connection_send_it(outgoing_con);
/* closing connection */
if (test->close_side == 0)
ret = sccp_connection_close(outgoing_con, 0);
else
ret = sccp_connection_close(incoming_con, 0);
if (ret != 0)
FAIL("Closing the connection failed\n");
}
/* outgoing should be gone now */
if (outgoing_con)
FAIL("Outgoing connection was not properly closed\n");
if (incoming_con)
FAIL("Incoming connection was not propery closed.\n");
if (test->refuse == 0) {
if (outgoing_data != 1 || incoming_data != 2) {
FAIL("Data sending failed: %d/%d %d/%d\n",
outgoing_data, 1,
incoming_data, 2);
}
}
if (!incoming_state || !outgoing_state)
FAIL("Failure with the state transition. %d %d\n",
outgoing_state, incoming_state);
}
static void test_sccp_connection(void)
{
sccp_system_init(sccp_write_loop, NULL);
sccp_set_read(NULL, NULL, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL);
test_data1 = msgb_alloc(4, "data1");
test_data1->l3h = msgb_put(test_data1, 4);
*((unsigned int*)test_data1->l3h) = 0x23421122;
test_data2 = msgb_alloc(4, "data2");
test_data2->l3h = msgb_put(test_data2, 4);
*((unsigned int*)test_data2->l3h) = 0x42232211;
test_data3 = msgb_alloc(4, "data3");
test_data3->l3h = msgb_put(test_data3, 4);
*((unsigned int*)test_data3->l3h) = 0x2323ff55;
for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) {
printf("Testing %d refuse: %d with_data: %d\n",
current_test, connection_tests[current_test].refuse,
connection_tests[current_test].with_data);
do_test_sccp_connection(&connection_tests[current_test]);
}
msgb_free(test_data1);
msgb_free(test_data2);
msgb_free(test_data3);
}
/* invalid input */
static void test_sccp_system_crash(void)
{
printf("trying to provoke a crash with invalid input\n");
sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
int original_length = test_data[current_test].length;
int length = original_length + 2;
int i;
printf("Testing packet: %d\n", current_test);
for (i = length; i >= 0; --i) {
unsigned int length = MIN(test_data[current_test].length, i);
struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
msg->l2h = msgb_put(msg, length);
memcpy(msg->l2h, test_data[current_test].data, length);
sccp_system_incoming(msg);
msgb_free(msg);
}
}
printf("survived\n");
}
static void test_sccp_parsing(void)
{
for (current_test = 0; current_test < ARRAY_SIZE(parse_result); ++current_test) {
struct msgb *msg;
struct sccp_parse_result result;
msg = msgb_alloc_headroom(1024, 128, "parse-test");
msgb_put(msg, 1);
msg->l2h = msgb_put(msg, parse_result[current_test].input_len);
memcpy(msg->l2h, parse_result[current_test].input, msgb_l2len(msg));
memset(&result, 0, sizeof(result));
if (sccp_parse_header(msg, &result) != 0) {
fprintf(stderr, "Failed to sccp parse test: %d\n", current_test);
} else {
if (parse_result[current_test].wanted_len != result.data_len) {
fprintf(stderr, "Unexpected data length.\n");
abort();
}
if (parse_result[current_test].has_src_ref) {
if (memcmp(result.source_local_reference,
&parse_result[current_test].src_ref,
sizeof(struct sccp_source_reference)) != 0) {
fprintf(stderr, "SRC REF did not match\n");
abort();
}
}
if (parse_result[current_test].has_dst_ref) {
if (memcmp(result.destination_local_reference,
&parse_result[current_test].dst_ref,
sizeof(struct sccp_source_reference)) != 0) {
fprintf(stderr, "DST REF did not match\n");
abort();
}
}
if (parse_result[current_test].src_ssn != -1) {
fprintf(stderr, "Not implemented.\n");
abort();
}
if (parse_result[current_test].dst_ssn != -1) {
fprintf(stderr, "Not implemented.\n");
abort();
}
}
msgb_free(msg);
}
}
int main(int argc, char **argv)
{
test_sccp_system();
test_sccp_send_udt();
test_sccp_udt_communication();
test_sccp_connection();
test_sccp_system_crash();
test_sccp_parsing();
return 0;
}
void db_store_counter() {}