Implement AoIP, port to M3UA SIGTRAN (large addition and refactoring)

This was originally a long series of commits converging to the final result
seen in this patch. It does not make much sense to review the smaller steps'
trial and error, we need to review this entire change as a whole.

Implement AoIP in osmo-msc and osmo-bsc.

Change over to the new libosmo-sigtran API with support for proper
SCCP/M3UA/SCTP stacking, as mandated by 3GPP specifications for the IuCS and
IuPS interfaces.

From here on, a separate osmo-stp process is required for SCCP routing between
OsmoBSC / OsmoHNBGW <-> OsmoMSC / OsmoSGSN

jenkins.sh: build from libosmo-sccp and osmo-iuh master branches now for new
M3UA SIGTRAN.

Patch-by: pmaier, nhofmeyr, laforge
Change-Id: I5ae4e05ee7c57cad341ea5e86af37c1f6b0ffa77
changes/86/3486/6
Philipp Maier 6 years ago committed by Harald Welte
parent 09e2c9f07d
commit fbf6610dc1
  1. 2
      configure.ac
  2. 9
      contrib/jenkins.sh
  3. 8
      doc/examples/osmo-bsc/osmo-bsc.cfg
  4. 4
      include/openbsc/Makefile.am
  5. 76
      include/openbsc/a_iface.h
  6. 41
      include/openbsc/a_iface_bssap.h
  7. 63
      include/openbsc/a_reset.h
  8. 12
      include/openbsc/bsc_msc.h
  9. 32
      include/openbsc/bsc_msc_data.h
  10. 1
      include/openbsc/debug.h
  11. 2
      include/openbsc/gsm_04_08.h
  12. 39
      include/openbsc/gsm_data.h
  13. 10
      include/openbsc/gsm_data_shared.h
  14. 13
      include/openbsc/iu.h
  15. 28
      include/openbsc/mgcpgw_client.h
  16. 20
      include/openbsc/msc_ifaces.h
  17. 6
      include/openbsc/osmo_bsc.h
  18. 34
      include/openbsc/osmo_bsc_reset.h
  19. 48
      include/openbsc/osmo_bsc_sigtran.h
  20. 7
      include/openbsc/osmo_msc.h
  21. 10
      include/openbsc/transaction.h
  22. 2
      src/gprs/Makefile.am
  23. 17
      src/gprs/sgsn_main.c
  24. 3
      src/libbsc/abis_rsl.c
  25. 81
      src/libbsc/bsc_vty.c
  26. 3
      src/libbsc/handover_logic.c
  27. 1
      src/libcommon-cs/Makefile.am
  28. 224
      src/libcommon-cs/a_reset.c
  29. 2
      src/libcommon-cs/common_cs.c
  30. 20
      src/libcommon/common_vty.c
  31. 6
      src/libcommon/debug.c
  32. 138
      src/libiu/iu.c
  33. 27
      src/libiu/iu_vty.c
  34. 44
      src/libmgcp/mgcp_protocol.c
  35. 95
      src/libmgcp/mgcpgw_client.c
  36. 51
      src/libmgcp/mgcpgw_client_vty.c
  37. 2
      src/libmsc/Makefile.am
  38. 582
      src/libmsc/a_iface.c
  39. 717
      src/libmsc/a_iface_bssap.c
  40. 207
      src/libmsc/gsm_04_08.c
  41. 3
      src/libmsc/gsm_subscriber.c
  42. 24
      src/libmsc/iucs.c
  43. 214
      src/libmsc/msc_ifaces.c
  44. 28
      src/libmsc/msc_vty.c
  45. 23
      src/libmsc/osmo_msc.c
  46. 3
      src/libmsc/subscr_conn.c
  47. 4
      src/osmo-bsc/Makefile.am
  48. 41
      src/osmo-bsc/osmo_bsc_api.c
  49. 70
      src/osmo-bsc/osmo_bsc_audio.c
  50. 307
      src/osmo-bsc/osmo_bsc_bssap.c
  51. 10
      src/osmo-bsc/osmo_bsc_main.c
  52. 62
      src/osmo-bsc/osmo_bsc_msc.c
  53. 190
      src/osmo-bsc/osmo_bsc_reset.c
  54. 328
      src/osmo-bsc/osmo_bsc_sccp.c
  55. 561
      src/osmo-bsc/osmo_bsc_sigtran.c
  56. 94
      src/osmo-bsc/osmo_bsc_vty.c
  57. 1
      src/osmo-bsc_mgcp/Makefile.am
  58. 1
      src/osmo-bsc_nat/Makefile.am
  59. 81
      src/osmo-msc/msc_main.c
  60. 7
      tests/msc_vlr/Makefile.am
  61. 36
      tests/msc_vlr/msc_vlr_test_gsm_authen.c
  62. 34
      tests/msc_vlr/msc_vlr_test_gsm_authen.err
  63. 30
      tests/msc_vlr/msc_vlr_test_gsm_ciph.c
  64. 28
      tests/msc_vlr/msc_vlr_test_gsm_ciph.err
  65. 22
      tests/msc_vlr/msc_vlr_test_hlr_reject.c
  66. 22
      tests/msc_vlr/msc_vlr_test_hlr_reject.err
  67. 4
      tests/msc_vlr/msc_vlr_test_hlr_timeout.c
  68. 4
      tests/msc_vlr/msc_vlr_test_hlr_timeout.err
  69. 6
      tests/msc_vlr/msc_vlr_test_ms_timeout.c
  70. 6
      tests/msc_vlr/msc_vlr_test_ms_timeout.err
  71. 26
      tests/msc_vlr/msc_vlr_test_no_authen.c
  72. 26
      tests/msc_vlr/msc_vlr_test_no_authen.err
  73. 30
      tests/msc_vlr/msc_vlr_test_reject_concurrency.c
  74. 38
      tests/msc_vlr/msc_vlr_test_reject_concurrency.err
  75. 13
      tests/msc_vlr/msc_vlr_test_rest.c
  76. 13
      tests/msc_vlr/msc_vlr_test_rest.err
  77. 23
      tests/msc_vlr/msc_vlr_test_umts_authen.c
  78. 15
      tests/msc_vlr/msc_vlr_test_umts_authen.err
  79. 37
      tests/msc_vlr/msc_vlr_tests.c
  80. 32
      tests/msc_vlr/msc_vlr_tests.h

@ -46,6 +46,7 @@ PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.9.5)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version?
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5)
# Enabke/disable the NAT?
@ -98,7 +99,6 @@ AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS a
if test "x$osmo_ac_iu" = "xyes" ; then
PKG_CHECK_MODULES(LIBASN1C, libasn1c) # TODO version?
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap) # TODO version?
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version?
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
fi
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")

@ -24,21 +24,16 @@ verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
if [ "x$IU" = "x--enable-iu" ]; then
sccp_branch="old_sua"
osmo_iuh_branch="old_sua"
fi
osmo-build-dep.sh libosmo-abis
osmo-build-dep.sh libosmo-netif
osmo-build-dep.sh libosmo-sccp $sccp_branch
osmo-build-dep.sh libosmo-sccp
PARALLEL_MAKE="" osmo-build-dep.sh libsmpp34
osmo-build-dep.sh openggsn
if [ "x$IU" = "x--enable-iu" ]; then
osmo-build-dep.sh libasn1c
#osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh
osmo-build-dep.sh osmo-iuh $osmo_iuh_branch
osmo-build-dep.sh osmo-iuh
fi
set +x

@ -81,7 +81,15 @@ network
timeslot 7
phys_chan_config TCH/F
hopping enabled 0
cs7 instance 1
point-code 3.0.0
sccp-address bsc_local
point-code 3.0.0
sccp-address msc_remote
point-code 1.0.0
msc
bsc-addr bsc_local
msc-addr msc_remote
ip.access rtp-base 4000
timeout-ping 20
timeout-pong 5

@ -2,6 +2,8 @@ noinst_HEADERS = \
abis_nm.h \
abis_om2000.h \
abis_rsl.h \
a_iface.h \
a_iface_bssap.h \
arfcn_range_encode.h \
auth.h \
bsc_msc.h \
@ -66,8 +68,10 @@ noinst_HEADERS = \
openbscdefines.h \
osmo_bsc.h \
osmo_bsc_grace.h \
a_reset.h \
osmo_bsc_rf.h \
osmo_msc.h \
osmo_bsc_sigtran.h \
bsc_msc_data.h \
osmux.h \
paging.h \

@ -0,0 +1,76 @@
/* (C) 2017 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <openbsc/a_reset.h>
/* A struct to keep a context information about the BSCs we are associated with */
struct bsc_context {
struct llist_head list;
/* Holds a copy of the sccp address of the BSC,
* this address will become known as soon as
* a remote BSC tries to make a connection or
* sends a RESET request via UNIDATA */
struct osmo_sccp_addr bsc_addr;
/* Holds a copy of the our local MSC address,
* this will be the sccp-address that is associated
* with the A interface */
struct osmo_sccp_addr msc_addr;
/* A pointer to the reset handler FSM, the
* state machine is allocated when the BSC
* is registerd. */
struct a_reset_ctx *reset;
/* A pointer to the sccp_user that is associated
* with the A interface. We need this information
* to send the resets and to send paging requests */
struct osmo_sccp_user *sccp_user;
};
/* Initalize A interface connection between to MSC and BSC */
int a_init(struct osmo_sccp_instance *sccp, struct gsm_network *network);
/* Send DTAP message via A-interface */
int a_iface_tx_dtap(struct msgb *msg);
/* Send Cipher mode command via A-interface */
int a_iface_tx_cipher_mode(const struct gsm_subscriber_connection *conn,
int cipher, const const uint8_t *key, int len, int include_imeisv);
/* Page a subscriber via A-interface */
int a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac);
/* Send assignment request via A-interface */
int a_iface_tx_assignment(const struct gsm_trans *trans);
/* Send clear command via A-interface */
int a_iface_tx_clear_cmd(struct gsm_subscriber_connection *conn);
/* Clear all subscriber connections on a specified BSC
* (Helper function for a_iface_bssap.c) */
void a_clear_all(struct osmo_sccp_user *scu, const struct osmo_sccp_addr *bsc_addr);
/* Delete info of a closed connection from the active connection list
* (Helper function for a_iface_bssap.c) */
void a_delete_bsc_con(uint32_t conn_id);

@ -0,0 +1,41 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/* Note: The structs and functions presented in this header file are intended
* to be used only by a_iface.c. */
/* A structure to hold tha most basic information about a sigtran connection
* we use this struct internally here to pass connection data around */
struct a_conn_info {
struct osmo_sccp_addr *msc_addr;
struct osmo_sccp_addr *bsc_addr;
uint32_t conn_id;
struct gsm_network *network;
struct a_reset_ctx *reset;
};
/* Receive incoming connection less data messages via sccp */
void sccp_rx_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);
/* Receive incoming connection oriented data messages via sccp */
int sccp_rx_dt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);

@ -0,0 +1,63 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/* Reset context data (callbacks, state machine etc...) */
struct a_reset_ctx {
/* FSM instance, which handles the reset procedure */
struct osmo_fsm_inst *fsm;
/* Connection failure counter. When this counter
* reaches a certain threshold, the reset procedure
* will be triggered */
int conn_loss_counter;
/* A human readable name to display in the logs */
char name[256];
/* Callback function to be called when a connection
* failure is detected and a rest must occur */
void (*cb)(void *priv);
/* Privated data for the callback function */
void *priv;
};
/* Create and start state machine which handles the reset/reset-ack procedure */
struct a_reset_ctx *a_reset_alloc(const void *ctx, const char *name, void *cb, void *priv);
/* Tear down state machine */
void a_reset_free(struct a_reset_ctx *reset);
/* Confirm that we sucessfully received a reset acknowlege message */
void a_reset_ack_confirm(struct a_reset_ctx *reset);
/* Report a failed connection */
void a_reset_conn_fail(struct a_reset_ctx *reset);
/* Report a successful connection */
void a_reset_conn_success(struct a_reset_ctx *reset);
/* Check if we have a connection to a specified msc */
bool a_reset_conn_ready(struct a_reset_ctx *reset);

@ -24,6 +24,8 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/a_reset.h>
#include <netinet/in.h>
@ -37,6 +39,7 @@ struct bsc_msc_dest {
struct bsc_msc_connection {
/* FIXME: Remove stuff that is no longer needed! */
struct osmo_wqueue write_queue;
int is_connected;
int is_authenticated;
@ -52,6 +55,15 @@ struct bsc_msc_connection {
struct osmo_timer_list timeout_timer;
struct msgb *pending_msg;
/* Sigtran connection data */
struct osmo_sccp_instance *sccp;
struct osmo_sccp_user *sccp_user;
struct osmo_sccp_addr g_calling_addr;
struct osmo_sccp_addr g_called_addr;
struct a_reset_ctx *reset;
int conn_id_counter;
};
struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest);

@ -32,6 +32,14 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/protocol/m3ua.h>
#include <osmocom/core/fsm.h>
#include <regex.h>
struct osmo_bsc_rf;
@ -103,6 +111,30 @@ struct bsc_msc_data {
char *ussd_grace_txt;
char *acc_lst_name;
/* Sigtran connection data */
struct {
uint32_t cs7_instance;
bool cs7_instance_valid;
struct osmo_sccp_instance *sccp;
struct osmo_sccp_user *sccp_user;
/* Holds a copy of the our local MSC address,
* this will be the sccp-address that is associated
* with the A interface of this particular BSC,
* this address is filled up by the VTY interface */
struct osmo_sccp_addr bsc_addr;
char *bsc_addr_name;
/* Holds a copy of the MSC address. This is the
* address of the MSC that handles the calls of
* this BSC. The address is configured via the
* VTY interface */
struct osmo_sccp_addr msc_addr;
char *msc_addr_name;
struct a_reset_ctx *reset;
} a;
};
/*

@ -40,6 +40,7 @@ enum {
DPCU,
DVLR,
DIUCS,
DSIGTRAN,
Debug_LastEntry,
};

@ -80,4 +80,6 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn);
int gsm48_multirate_config(uint8_t *lv, const struct amr_multirate_conf *mr, const struct amr_mode *modes);
int gsm48_tch_rtp_create(struct gsm_trans *trans);
#endif

@ -12,12 +12,14 @@
#include <osmocom/core/stats.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/common.h>
#include <openbsc/rest_octets.h>
#include <openbsc/common_cs.h>
#include <openbsc/mgcpgw_client.h>
/** annotations for msgb ownership */
#define __uses
@ -193,14 +195,33 @@ struct gsm_subscriber_connection {
uint16_t lac;
struct gsm_encr encr;
struct {
unsigned int mgcp_rtp_endpoint;
uint16_t port_subscr;
uint16_t port_cn;
} rtp;
/* which Iu-CS connection, if any. */
struct {
struct ue_conn_ctx *ue_ctx;
unsigned int mgcp_rtp_endpoint;
uint16_t mgcp_rtp_port_ue;
uint16_t mgcp_rtp_port_cn;
uint8_t rab_id;
} iu;
struct {
/* A pointer to the SCCP user that handles
* the SCCP connections for this subscriber
* connection */
struct osmo_sccp_user *scu;
/* The address of the BSC that is associated
* with this subscriber connection */
struct osmo_sccp_addr bsc_addr;
/* The connection identifier that is used
* to reference the SCCP connection that is
* associated with this subscriber connection */
int conn_id;
} a;
};
@ -470,8 +491,20 @@ struct gsm_network {
} mgcpgw;
struct {
/* CS7 instance id number (set via VTY) */
uint32_t cs7_instance;
enum nsap_addr_enc rab_assign_addr_enc;
struct osmo_sccp_instance *sccp;
} iu;
struct {
/* CS7 instance id number (set via VTY) */
uint32_t cs7_instance;
/* A list with the context information about
* all BSCs we have connections with */
struct llist_head bscs;
struct osmo_sccp_instance *sccp;
} a;
};
struct osmo_esme;

@ -252,6 +252,16 @@ struct gsm_lchan {
uint8_t speech_mode;
#ifdef ROLE_BSC
struct rtp_socket *rtp_socket;
/* info we need to postpone the AoIP
* assignment completed message */
struct {
uint8_t rr_cause;
uint8_t chosen_channel;
uint8_t encr_alg_id;
uint8_t speech_mode;
bool valid;
} ass_compl;
#else
struct osmo_rtp_socket *rtp_socket;
#endif

@ -5,13 +5,15 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <openbsc/common.h>
struct sgsn_pdp_ctx;
struct msgb;
struct osmo_sccp_link;
struct gsm_auth_tuple;
struct osmo_sccp_addr;
struct osmo_ss7_instance;
struct RANAP_RAB_SetupOrModifiedItemIEs_s;
struct RANAP_GlobalRNC_ID;
@ -23,7 +25,10 @@ extern int asn1_xer_print;
struct ue_conn_ctx {
struct llist_head list;
struct osmo_sccp_link *link;
/* TODO: It's not needed to store the full SCCP address for each
* UE. Rather than that, a pointer to the RNC should be far
* sufficient */
struct osmo_sccp_addr sccp_addr;
uint32_t conn_id;
int integrity_active;
struct gprs_ra_id ra_id;
@ -53,11 +58,9 @@ typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx,
typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id,
struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies);
int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
int iu_init(void *ctx, struct osmo_sccp_instance *sccp,
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb);
void iu_link_del(struct osmo_sccp_link *link);
int iu_tx(struct msgb *msg, uint8_t sapi);
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);

@ -3,11 +3,11 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/write_queue.h>
enum mgcp_connection_mode;
struct msgb;
struct mgcpgw_client;
struct vty;
#define MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
@ -24,6 +24,9 @@ struct mgcpgw_client_conf {
int local_port;
const char *remote_addr;
int remote_port;
uint16_t first_endpoint;
uint16_t last_endpoint;
uint16_t bts_base;
};
struct mgcp_response_head {
@ -38,6 +41,20 @@ struct mgcp_response {
uint16_t audio_port;
};
struct mgcpgw_client {
struct mgcpgw_client_conf actual;
uint32_t remote_addr;
struct osmo_wqueue wq;
mgcp_trans_id_t next_trans_id;
struct llist_head responses_pending;
struct llist_head inuse_endpoints;
};
struct mgcp_inuse_endpoint {
struct llist_head entry;
uint16_t id;
};
/* Invoked when an MGCP response is received or sending failed. When the
* response is passed as NULL, this indicates failure during transmission. */
typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
@ -61,7 +78,11 @@ const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp);
uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp);
uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp);
unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
/* Find and seize an unsused endpoint id */
int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
/* Release a seized endpoint id to make it available again for other calls */
void mgcpgw_client_release_endpoint(uint16_t id, struct mgcpgw_client *client);
int mgcp_response_parse_params(struct mgcp_response *r);
@ -76,6 +97,9 @@ struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
uint16_t rtp_endpoint, const char *rtp_conn_addr,
uint16_t rtp_port, enum mgcp_connection_mode mode);
struct msgb *mgcp_msg_dlcx(struct mgcpgw_client *mgcp, uint16_t rtp_endpoint,
unsigned int call_id);
void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf);
int mgcpgw_client_config_write(struct vty *vty, const char *indent);

@ -28,20 +28,6 @@
/* Each main linkage must implement this function (see comment above). */
extern int iu_tx(struct msgb *msg, uint8_t sapi);
/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
* gets implemented, it should be in a separate lib (like libiu), this function
* should move there, and the following comment should remain here: "
* Each main linkage must implement this function (see comment above).
* " */
extern int a_tx(struct msgb *msg);
/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
* gets implemented, it should be in a separate lib (like libiu), this function
* should move there, and the following comment should remain here: "
* Each main linkage must implement this function (see comment above).
* " */
extern int a_page(const char *imsi, uint32_t tmsi, uint16_t lac);
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg);
@ -49,10 +35,8 @@ int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn);
int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value);
/* TODO: specific to A interface, move this away */
int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
const uint8_t *key, int len, int include_imeisv);
int msc_tx_common_id(struct gsm_subscriber_connection *conn);
int msc_call_assignment(struct gsm_trans *trans);
int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2);
void msc_call_release(struct gsm_trans *trans);
int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip);

@ -26,6 +26,7 @@ struct osmo_bsc_sccp_con {
/* for audio handling */
uint16_t cic;
uint32_t rtp_ip;
int rtp_port;
/* for advanced ping/pong */
@ -44,6 +45,9 @@ struct osmo_bsc_sccp_con {
uint8_t new_subscriber;
struct bsc_filter_state filter_state;
/* Sigtran connection ID */
int conn_id;
};
struct bsc_api *osmo_bsc_api();
@ -60,7 +64,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn);
int bsc_handle_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_handle_dt(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install();

@ -0,0 +1,34 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* Create and start state machine which handles the reset/reset-ack procedure */
void start_reset_fsm(struct bsc_msc_data *msc);
/* Confirm that we sucessfully received a reset acknowlege message */
void reset_ack_confirm(struct bsc_msc_data *msc);
/* Report a failed connection */
void report_conn_fail(struct bsc_msc_data *msc);
/* Report a successful connection */
void report_conn_success(struct bsc_msc_data *msc);
/* Check if we have a connection to a specified msc */
bool sccp_conn_ready(struct bsc_msc_data *msc);

@ -0,0 +1,48 @@
/* (C) 2017 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <openbsc/gsm_data.h>
#include <openbsc/bsc_msc_data.h>
/* Allocate resources to make a new connection oriented sigtran connection
* (not the connection ittself!) */
enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc);
/* Open a new connection oriented sigtran connection */
int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg);
/* Send data to MSC */
int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg);
/* Delete a connection from the list with open connections
* (called by osmo_bsc_api.c on failing open connections and
* locally, when a connection is closed by the MSC */
int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *sccp);
/* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs);
/* Close all open sigtran connections and channels */
void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc);
/* Send reset-ack to MSC */
void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc);

@ -63,6 +63,8 @@ int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id);
int msc_vlr_alloc(struct gsm_network *net);
int msc_vlr_start(struct gsm_network *net);
void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci);
int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
int msc_compl_l3(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint16_t chosen_channel);
void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id,
@ -70,6 +72,11 @@ void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id,
void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint8_t alg_id);
void msc_rx_sec_mode_compl(struct gsm_subscriber_connection *conn);
void msc_classmark_chg(struct gsm_subscriber_connection *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len);
void msc_assign_fail(struct gsm_subscriber_connection *conn,
uint8_t cause, uint8_t *rr_cause);
void msc_subscr_conn_init(void);
bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn);

@ -46,6 +46,16 @@ struct gsm_trans {
/* is thats one paging? */
struct subscr_request *paging_request;
/* bearer capabilities (rate and codec) */
struct gsm_mncc_bearer_cap bearer_cap;
/* status of the assignment, true when done */
bool assignment_done;
/* if true, TCH_RTP_CREATE is sent after the
* assignment is done */
bool tch_rtp_create;
union {
struct {

@ -34,6 +34,7 @@ OSMO_LIBS = \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBGTP_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
$(NULL)
bin_PROGRAMS = \
@ -128,5 +129,6 @@ osmo_gtphub_LDADD = \
$(LIBOSMOVTY_LIBS) \
$(LIBCARES_LIBS) \
$(LIBGTP_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
-lrt \
$(NULL)

@ -63,6 +63,8 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/sigtran/protocol/m3ua.h>
#include <gtp.h>
#include "../../bscconfig.h"
@ -326,6 +328,7 @@ int main(int argc, char **argv)
{
struct ctrl_handle *ctrl;
struct gsm_network dummy_network;
struct osmo_sccp_instance *sccp;
int rc;
srand(time(NULL));
@ -348,6 +351,7 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds(&gprs_log_info);
sgsn_vty_init(&sgsn_inst.cfg);
ctrl_vty_init(tall_bsc_ctx);
osmo_ss7_init();
handle_options(argc, argv);
@ -436,7 +440,18 @@ int main(int argc, char **argv)
}
#ifdef BUILD_IU
iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
sccp = osmo_sccp_simple_client(tall_bsc_ctx, "OsmoSGSN",
2 /* FIXME: configurable */,
OSMO_SS7_ASP_PROT_M3UA, 0,
"127.0.0.4" /* FIXME: configurable */,
M3UA_PORT,
"127.0.0.1" /* FIXME: configurable */);
if (!sccp) {
printf("Setting up SCCP client failed.\n");
return 8;
}
iu_init(tall_bsc_ctx, sccp, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
#endif
if (daemonize) {

@ -2327,6 +2327,8 @@ static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
DEBUGPC(DRSL, "REMOTE_PORT=%u ", port);
lchan->abis_ip.connect_port = port;
}
DEBUGPC(DRSL, "\n");
}
/*! \brief Issue IPA RSL CRCX to configure RTP on BTS side
@ -2558,7 +2560,6 @@ static int abis_rsl_rx_ipacc(struct msgb *msg)
rllh->c.msg_type);
break;
}
DEBUGPC(DRSL, "\n");
return rc;
}

@ -57,6 +57,7 @@
#include <openbsc/pcu_if.h>
#include <openbsc/common_cs.h>
#include <openbsc/vlr.h>
#include <openbsc/handover.h>
#include <inttypes.h>
@ -1341,6 +1342,83 @@ DEFUN(show_lchan_summary,
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
DEFUN(show_subscr_conn,
show_subscr_conn_cmd,
"show conns",
SHOW_STR "Display currently active subscriber connections\n")
{
struct gsm_subscriber_connection *conn;
struct gsm_network *net = gsmnet_from_vty(vty);
bool no_conns = true;
unsigned int count = 0;
vty_out(vty, "Active subscriber connections: %s", VTY_NEWLINE);
llist_for_each_entry(conn, &net->subscr_conns, entry) {
vty_out(vty, "conn nr #%u:%s", count, VTY_NEWLINE);
lchan_dump_full_vty(vty, conn->lchan);
no_conns = false;
count++;
}
if (no_conns)
vty_out(vty, "None%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(handover_subscr_conn,
handover_subscr_conn_cmd,
"handover <0-255> <0-255> <0-7> LCHAN_NR <0-255>",
"Handover subscriber connection to other BTS\n"
"BTS Number (current)\n" "TRX Number\n" "Timeslot Number\n"
LCHAN_NR_STR "BTS Number (new)\n")
{
struct gsm_network *net = gsmnet_from_vty(vty);
struct gsm_subscriber_connection *conn;
struct gsm_bts *bts;
struct gsm_bts *new_bts = NULL;
unsigned int bts_nr = atoi(argv[0]);
unsigned int trx_nr = atoi(argv[1]);
unsigned int ts_nr = atoi(argv[2]);
unsigned int ss_nr = atoi(argv[3]);
unsigned int bts_nr_new = atoi(argv[4]);
/* Lookup the BTS where we want to handover to */
llist_for_each_entry(bts, &net->bts_list, list) {
if (bts->nr == bts_nr_new) {
new_bts = bts;
break;
}
}
if (!new_bts) {
vty_out(vty, "Unable to trigger handover,"
"specified bts #%u does not exist %s", bts_nr_new,
VTY_NEWLINE);
return CMD_WARNING;
}
/* Find the connection/lchan that we want to handover */
llist_for_each_entry(conn, &net->subscr_conns, entry) {
if (conn->bts->nr == bts_nr &&
conn->lchan->ts->trx->nr == trx_nr &&
conn->lchan->ts->nr == ts_nr && conn->lchan->nr == ss_nr) {
vty_out(vty, "starting handover for lchan %s...%s",
conn->lchan->name, VTY_NEWLINE);
lchan_dump_full_vty(vty, conn->lchan);
bsc_handover_start(conn->lchan, new_bts);
return CMD_SUCCESS;
}
}
vty_out(vty, "Unable to trigger handover,"
"specified connection (bts=%u,trx=%u,ts=%u,ss=%u) does not exist%s",
bts_nr, trx_nr, ts_nr, ss_nr, VTY_NEWLINE);
return CMD_WARNING;
}
static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
{
vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
@ -4153,6 +4231,9 @@ int bsc_vty_init(struct gsm_network *network)
install_element_ve(&show_lchan_cmd);
install_element_ve(&show_lchan_summary_cmd);
install_element_ve(&show_subscr_conn_cmd);
install_element_ve(&handover_subscr_conn_cmd);
install_element_ve(&show_paging_cmd);
install_element_ve(&show_paging_group_cmd);

@ -101,7 +101,8 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
if (bsc_ho_by_old_lchan(old_lchan))
return -EBUSY;
DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
DEBUGP(DHO, "Beginning with handover operation"
"(old_lchan on BTS %u, new BTS %u) ...\n",
old_lchan->ts->trx->bts->nr, bts->nr);
rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]);

@ -16,5 +16,6 @@ AM_CFLAGS = \
noinst_LIBRARIES = libcommon-cs.a
libcommon_cs_a_SOURCES = \
a_reset.c \
common_cs.c \
common_cs_vty.c

@ -0,0 +1,224 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/fsm.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <openbsc/debug.h>
#include <openbsc/bsc_msc_data.h>
#include <openbsc/osmo_bsc_sigtran.h>
#define RESET_RESEND_INTERVAL 2 /* sec */
#define RESET_RESEND_TIMER_NO 1234 /* FIXME: dig out the real timer number */
#define BAD_CONNECTION_THRESOLD 3 /* connection failures */
enum fsm_states {
ST_DISC, /* Disconnected from remote end */
ST_CONN, /* We have a confirmed connection */
};
static const struct value_string fsm_state_names[] = {
{ST_DISC, "ST_DISC (disconnected)"},
{ST_CONN, "ST_CONN (connected)"},
{0, NULL},
};
enum fsm_evt {
EV_RESET_ACK, /* got reset acknowlegement from remote end */
EV_N_DISCONNECT, /* lost a connection */
EV_N_CONNECT, /* made a successful connection */
};
static const struct value_string fsm_evt_names[] = {
{EV_RESET_ACK, "EV_RESET_ACK"},
{EV_N_DISCONNECT, "EV_N_DISCONNECT"},
{EV_N_CONNECT, "EV_N_CONNECT"},
{0, NULL},
};
/* Disconnected state */
static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct a_reset_ctx *reset = (struct a_reset_ctx *)data;
OSMO_ASSERT(reset);
LOGP(DMSC, LOGL_NOTICE, "(%s) fsm-state (msc-reset): %s, fsm-event: %s\n", reset->name,
get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event));
reset->conn_loss_counter = 0;
osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
}
/* Connected state */
static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct a_reset_ctx *reset = (struct a_reset_ctx *)data;
OSMO_ASSERT(reset);
LOGP(DMSC, LOGL_NOTICE, "(%s) fsm-state (msc-reset): %s, fsm-event: %s\n", reset->name,
get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event));
switch (event) {
case EV_N_DISCONNECT:
if (reset->conn_loss_counter >= BAD_CONNECTION_THRESOLD) {
LOGP(DMSC, LOGL_NOTICE, "(%s) SIGTRAN connection down, reconnecting...\n", reset->name);
osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
} else
reset->conn_loss_counter++;
break;
case EV_N_CONNECT:
reset->conn_loss_counter = 0;
break;
}
}
/* Timer callback to retransmit the reset signal */
static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
{
struct a_reset_ctx *reset = (struct a_reset_ctx *)fi->priv;
LOGP(DMSC, LOGL_NOTICE, "(%s) reset-ack timeout (T%i) in state %s, resending...\n", reset->name, fi->T,
get_value_string(fsm_state_names, fi->state));
reset->cb(reset->priv);
osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
return 0;
}
static struct osmo_fsm_state fsm_states[] = {
[ST_DISC] = {
.in_event_mask = (1 << EV_RESET_ACK),
.out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
.name = "DISC",
.action = fsm_disc_cb,
},
[ST_CONN] = {
.in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT),
.out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
.name = "CONN",
.action = fsm_conn_cb,
},
};
/* State machine definition */
static struct osmo_fsm fsm = {
.name = "FSM RESET",
.states = fsm_states,
.num_states = ARRAY_SIZE(fsm_states),
.log_subsys = DMSC,
.timer_cb = fsm_reset_ack_timeout_cb,
};
/* Create and start state machine which handles the reset/reset-ack procedure */
struct a_reset_ctx *a_reset_alloc(const void *ctx, const char *name, void *cb, void *priv)
{
OSMO_ASSERT(name);
struct a_reset_ctx *reset;
/* Register the fsm description (if not already done) */
if (osmo_fsm_find_by_name(fsm.name) != &fsm)
osmo_fsm_register(&fsm);
/* Allocate and configure a new fsm instance */
reset = talloc_zero(ctx, struct a_reset_ctx);
OSMO_ASSERT(reset);
reset->priv = priv;
reset->cb = cb;
strncpy(reset->name, name, sizeof(reset->name));
reset->conn_loss_counter = 0;
reset->fsm = osmo_fsm_inst_alloc(&fsm, NULL, NULL, LOGL_DEBUG, "FSM RESET INST");
OSMO_ASSERT(reset->fsm);
reset->fsm->priv = reset;
LOGP(DMSC, LOGL_NOTICE, "(%s) reset handler fsm created.\n", reset->name);
/* kick off reset-ack sending mechanism */
osmo_fsm_inst_state_chg(reset->fsm, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
return reset;
}
/* Tear down state machine */
void a_reset_free(struct a_reset_ctx *reset)
{
OSMO_ASSERT(reset);
OSMO_ASSERT(reset->fsm);
osmo_fsm_inst_free(reset->fsm);
reset->fsm = NULL;
memset(reset, 0, sizeof(*reset));
talloc_free(reset);
LOGP(DMSC, LOGL_NOTICE, "(%s) reset handler fsm destroyed.\n", reset->name);
}
/* Confirm that we sucessfully received a reset acknowlege message */
void a_reset_ack_confirm(struct a_reset_ctx *reset)
{
OSMO_ASSERT(reset);
OSMO_ASSERT(reset->fsm);
osmo_fsm_inst_dispatch(reset->fsm, EV_RESET_ACK, reset);
}
/* Report a failed connection */
void a_reset_conn_fail(struct a_reset_ctx *reset)
{
/* If no reset context is supplied, just drop the info */
if (!reset)
return;
OSMO_ASSERT(reset->fsm);
osmo_fsm_inst_dispatch(reset->fsm, EV_N_DISCONNECT, reset);
}
/* Report a successful connection */
void a_reset_conn_success(struct a_reset_ctx *reset)
{
/* If no reset context is supplied, just drop the info */
if (!reset)
return;
OSMO_ASSERT(reset->fsm);
osmo_fsm_inst_dispatch(reset->fsm, EV_N_CONNECT, reset);
}
/* Check if we have a connection to a specified msc */
bool a_reset_conn_ready(struct a_reset_ctx *reset)
{
/* If no reset context is supplied, we assume that
* the connection can't be ready! */
if (!reset)
return false;
OSMO_ASSERT(reset->fsm);
if (reset->fsm->state == ST_CONN)
return true;
return false;
}

@ -78,6 +78,8 @@ struct gsm_network *gsm_network_init(void *ctx,
net->dyn_ts_allow_tch_f = true;
INIT_LLIST_HEAD(&net->a.bscs);
return net;
}

@ -34,6 +34,7 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/vty.h>
#include <osmocom/sigtran/osmo_ss7.h>
int bsc_vty_go_parent(struct vty *vty)
@ -117,13 +118,15 @@ int bsc_vty_go_parent(struct vty *vty)
case MSC_NODE:
case MNCC_INT_NODE:
case NITB_NODE:
default:
if (bsc_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;
else
vty->node = ENABLE_NODE;
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
case SUBSCR_NODE:
vty->node = ENABLE_NODE;
vty->index = NULL;
break;
default:
osmo_ss7_vty_go_parent(vty);
}
return vty->node;
@ -131,6 +134,11 @@ int bsc_vty_go_parent(struct vty *vty)
int bsc_vty_is_config_node(struct vty *vty, int node)
{
/* Check if libosmo-sccp declares the node in
* question as config node */
if