aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-06-23 14:43:55 +0200
committerPhilipp Maier <pmaier@sysmocom.de>2017-06-28 13:35:10 +0200
commit40703dd1f441ee754a3b9b8b838feb66bc8e032d (patch)
tree7f870f861931021464144bc2f59e4c19640d1384 /openbsc/src/libmsc
parent030312043a84b0bfaf35c36790e56e3016c68661 (diff)
a_iface: use vty to configure BSC/MSC connections
Use the VTY to configure the connections between BSC and MSC on both sides. We now can add new connections, we also can write the config, removing existing connections is implemented on the MSC side, but not yet on the BSC side.
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r--openbsc/src/libmsc/a_iface.c131
-rw-r--r--openbsc/src/libmsc/msc_vty.c104
2 files changed, 191 insertions, 44 deletions
diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c
index fbd5b9329..1ebb645fa 100644
--- a/openbsc/src/libmsc/a_iface.c
+++ b/openbsc/src/libmsc/a_iface.c
@@ -115,9 +115,9 @@ static struct a_reset_ctx *get_reset_ctx_by_sccp_addr(struct osmo_sccp_addr *add
if (!addr)
return NULL;
- llist_for_each_entry(bsc_ctx, &gsm_network->bscs, list) {
+ llist_for_each_entry(bsc_ctx, &gsm_network->a.bscs, list) {
if (memcmp(&bsc_ctx->called_addr, addr, sizeof(*addr)) == 0)
- return &bsc_ctx->reset;
+ return bsc_ctx->reset;
}
LOGP(DMSC, LOGL_ERROR, "The calling BSC (%s) is unknown to this MSC ...\n",
@@ -199,8 +199,8 @@ int a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac)
cil.id_list_len = 1;
/* Deliver paging request to all known BSCs */
- llist_for_each_entry(bsc_ctx, &gsm_network->bscs, list) {
- if (a_reset_conn_ready(&bsc_ctx->reset)) {
+ llist_for_each_entry(bsc_ctx, &gsm_network->a.bscs, list) {
+ if (a_reset_conn_ready(bsc_ctx->reset)) {
LOGP(DMSC, LOGL_DEBUG,
"Passing paging message from MSC %s to BSC %s (imsi=%s, tmsi=0x%08x, lac=%u)\n",
osmo_sccp_addr_dump(&bsc_ctx->calling_addr),
@@ -444,7 +444,6 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
a_conn_info.called_addr = &scu_prim->u.unitdata.called_addr;
a_conn_info.calling_addr = &scu_prim->u.unitdata.calling_addr;
a_conn_info.reset = get_reset_ctx_by_sccp_addr(&scu_prim->u.unitdata.calling_addr);
-
DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
sccp_rx_udt(scu, &a_conn_info, oph->msg);
break;
@@ -487,61 +486,105 @@ static void a_reset_cb(void *priv)
struct msgb *msg;
struct bsc_context *bsc_ctx = (struct bsc_context*) priv;
+ /* Skip if the A interface is not properly initalized yet */
+ if (!gsm_network)
+ return;
+
/* Clear all now orphaned subscriber connections */
a_clear_all(bsc_ctx->sccp_user, &bsc_ctx->called_addr);
+ /* Send reset to the remote BSC */
LOGP(DMSC, LOGL_NOTICE, "Sending RESET to BSC %s\n", osmo_sccp_addr_dump(&bsc_ctx->called_addr));
msg = gsm0808_create_reset();
osmo_sccp_tx_unitdata_msg(bsc_ctx->sccp_user, &bsc_ctx->calling_addr,
&bsc_ctx->called_addr, msg);
}
-/* Initalize A interface connection between to MSC and BSC */
-int a_init(void *ctx, const char *name, uint32_t local_pc,
- const char *listen_addr, const char *remote_addr, uint16_t local_port, struct gsm_network *network)
+/* Initalize a new A connection for a remote bsc (called by VTY) */
+int a_init(struct gsm_network *network, struct osmo_sccp_addr *calling_addr, struct osmo_sccp_addr *called_addr,
+ struct osmo_ss7_instance *ss7)
{
+ struct bsc_context *bsc_ctx;
+ OSMO_ASSERT(network);
+ OSMO_ASSERT(calling_addr);
+ OSMO_ASSERT(called_addr);
+ OSMO_ASSERT(ss7);
-#define SSN_BSSAP 254 /* SCCP_SSN_BSSAP */
-#define SENDER_PC 1 /* Our local point code */
-
- /* FIXME: Remove hardcoded parameters, use parameters in parameter list */
- struct osmo_sccp_instance *sccp;
- struct osmo_sccp_user *scu;
- struct bsc_context *bsc_ctx;
+ /* Set GSM network variable */
+ /* NOTE: There can only be one gsm network! */
+ if (gsm_network != NULL) {
+ OSMO_ASSERT(gsm_network == network);
+ } else
+ gsm_network = network;
- LOGP(DMSC, LOGL_NOTICE, "Initalizing SCCP connection to stp...\n");
+ /* Generate and fill up a new bsc context */
+ bsc_ctx = talloc_zero(gsm_network, struct bsc_context);
+ OSMO_ASSERT(bsc_ctx);
- gsm_network = network;
- osmo_ss7_init();
+ snprintf(bsc_ctx->name, sizeof(bsc_ctx->name), "%s/%s", osmo_sccp_name_by_addr(calling_addr, ss7),
+ osmo_sccp_name_by_addr(called_addr, ss7));
- /* SCCP Protocol stack */
- sccp =
- osmo_sccp_simple_client(NULL, "osmo-msc", SENDER_PC, OSMO_SS7_ASP_PROT_M3UA, 0, NULL, M3UA_PORT,
+ bsc_ctx->ss7 = ss7;
+ bsc_ctx->sccp =
+ osmo_sccp_simple_client(NULL, bsc_ctx->name, calling_addr->pc, OSMO_SS7_ASP_PROT_M3UA, 0, NULL, M3UA_PORT,
"127.0.0.1");
- scu = osmo_sccp_user_bind(sccp, "osmo-msc", sccp_sap_up, SSN_BSSAP);
-
- /* Add some BSCs to the context list */
- /* FIXME: Make this configurable (VTY!) */
- bsc_ctx = talloc_zero(NULL, struct bsc_context);
- bsc_ctx->reset.priv = bsc_ctx;
- bsc_ctx->reset.cb = a_reset_cb;
- llist_add_tail(&bsc_ctx->list, &gsm_network->bscs);
- bsc_ctx->called_addr.presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC;
- bsc_ctx->called_addr.ssn = SCCP_SSN_BSSAP;
- bsc_ctx->called_addr.ri = OSMO_SCCP_RI_SSN_PC;
- bsc_ctx->called_addr.pc = 23;
- bsc_ctx->calling_addr.presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC;
- bsc_ctx->calling_addr.ssn = SCCP_SSN_BSSAP;
- bsc_ctx->calling_addr.ri = OSMO_SCCP_RI_SSN_PC;
- bsc_ctx->calling_addr.pc = 1;
- bsc_ctx->sccp_user = scu;
- bsc_ctx = NULL;
-
- /* Start reset procedure for all BSC connections */
- llist_for_each_entry(bsc_ctx, &gsm_network->bscs, list) {
- a_reset_start(&bsc_ctx->reset);
- }
+ bsc_ctx->sccp_user = osmo_sccp_user_bind(bsc_ctx->sccp, bsc_ctx->name, sccp_sap_up, SCCP_SSN_BSSAP);
+
+ memcpy(&bsc_ctx->called_addr, called_addr, sizeof(*called_addr));
+ memcpy(&bsc_ctx->calling_addr, calling_addr, sizeof(*calling_addr));
+
+ llist_add_tail(&bsc_ctx->list, &gsm_network->a.bscs);
+
+ /* Start reset procedure to make the new connection active */
+ bsc_ctx->reset = a_reset_alloc(bsc_ctx, bsc_ctx->name, a_reset_cb, bsc_ctx);
+
+ LOGP(DMSC, LOGL_NOTICE, "Adding new MSC/BSC connection (%s), MSC=%s,", bsc_ctx->name,
+ osmo_sccp_addr_dump(calling_addr));
+ LOGPC(DMSC, LOGL_NOTICE, " BSC=%s...\n", osmo_sccp_addr_dump(called_addr));
return 0;
}
+
+/* Drop a no longer used A connection (called by VTY) */
+void a_drop(struct osmo_sccp_addr *calling_addr, struct osmo_sccp_addr *called_addr)
+{
+ struct bsc_context *bsc_ctx;
+ struct bsc_context *bsc_ctx_temp;
+
+ OSMO_ASSERT(calling_addr);
+ OSMO_ASSERT(called_addr);
+
+ /* Find the BSC context depending on the given addresses */
+ llist_for_each_entry_safe(bsc_ctx, bsc_ctx_temp, &gsm_network->a.bscs, list) {
+ if (memcmp(&bsc_ctx->calling_addr, calling_addr, sizeof(*calling_addr)) == 0
+ && memcmp(&bsc_ctx->called_addr, called_addr, sizeof(*called_addr)) == 0) {
+
+ OSMO_ASSERT(bsc_ctx->ss7);
+ OSMO_ASSERT(bsc_ctx->sccp);
+ OSMO_ASSERT(bsc_ctx->sccp_user);
+
+ LOGP(DMSC, LOGL_NOTICE, "Removing MSC/BSC connection (%s), MSC=%s,", bsc_ctx->name,
+ osmo_sccp_addr_dump(calling_addr));
+ LOGPC(DMSC, LOGL_NOTICE, " BSC=%s...\n", osmo_sccp_addr_dump(called_addr));
+
+ /* Perform the reset procedure one last time. This will also tear
+ * down all currently open connections. */
+ bsc_ctx->reset->cb(bsc_ctx->reset->priv);
+
+ /* Destroy reset handler FSM, reconnecting is no longer impossible */
+ a_reset_free(bsc_ctx->reset);
+
+ /* Destroy ss7 connection */
+ osmo_sccp_user_unbind(bsc_ctx->sccp_user);
+ osmo_sccp_instance_destroy(bsc_ctx->sccp);
+
+ /* Exterminate bsc context */
+ llist_del(&bsc_ctx->list);
+ memset(bsc_ctx, 0, sizeof(*bsc_ctx));
+ talloc_free(bsc_ctx);
+
+ return;
+ }
+ }
+}
diff --git a/openbsc/src/libmsc/msc_vty.c b/openbsc/src/libmsc/msc_vty.c
index b6fff56af..b9519ceeb 100644
--- a/openbsc/src/libmsc/msc_vty.c
+++ b/openbsc/src/libmsc/msc_vty.c
@@ -32,6 +32,8 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/vlr.h>
#include <openbsc/iu.h>
+#include <openbsc/a_iface.h>
+#include <osmocom/sccp/sccp_types.h>
static struct cmd_node msc_node = {
MSC_NODE,
@@ -105,9 +107,96 @@ DEFUN(cfg_msc_no_assign_tmsi, cfg_msc_no_assign_tmsi_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_msc_register_bsc, cfg_msc_register_bsc_cmd,
+ "bsc cs7-instance <0-15> calling-addr NAME called-addr NAME",
+ "Register a new BSC connection to this MSC.\n"
+ "Associated SS7 instance\n"
+ "SS7 instance reference number\n"
+ "Calling Address (local address of this MSC)\n"
+ "SCCP address name\n"
+ "Called Address (remote address of the BSC)\n" "SCCP address name\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ struct osmo_sccp_addr *calling_addr;
+ struct osmo_sccp_addr *called_addr;
+ struct osmo_ss7_instance *inst;
+
+ uint32_t inst_id = atoi(argv[0]);
+ const char *calling_addr_name = argv[1];
+ const char *called_addr_name = argv[2];
+
+ inst = osmo_ss7_instance_find(inst_id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", inst_id,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ calling_addr = osmo_sccp_addr_by_name(calling_addr_name, inst);
+ if (!calling_addr) {
+ vty_out(vty, "No sccp address %s found%s", calling_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ called_addr = osmo_sccp_addr_by_name(called_addr_name, inst);
+ if (!called_addr) {
+ vty_out(vty, "No sccp address %s found%s", called_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ a_init(gsmnet, calling_addr, called_addr, inst);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_msc_no_register_bsc, cfg_msc_no_register_bsc_cmd,
+ "no bsc cs7-instance <0-15> calling-addr NAME called-addr NAME",
+ NO_STR
+ "Remove a BSC connection to this MSC.\n"
+ "Associated SS7 instance\n"
+ "SS7 instance reference number\n"
+ "Calling Address (local address of this MSC)\n"
+ "SCCP address name\n"
+ "Called Address (remote address of the BSC)\n" "SCCP address name\n")
+{
+ struct osmo_sccp_addr *calling_addr;
+ struct osmo_sccp_addr *called_addr;
+ struct osmo_ss7_instance *inst;
+
+ uint32_t inst_id = atoi(argv[0]);
+ const char *calling_addr_name = argv[1];
+ const char *called_addr_name = argv[2];
+
+ inst = osmo_ss7_instance_find(inst_id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", inst_id,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ calling_addr = osmo_sccp_addr_by_name(calling_addr_name, inst);
+ if (!calling_addr) {
+ vty_out(vty, "No sccp address %s found%s", calling_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ called_addr = osmo_sccp_addr_by_name(called_addr_name, inst);
+ if (!called_addr) {
+ vty_out(vty, "No sccp address %s found%s", called_addr_name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ a_drop(calling_addr, called_addr);
+ return CMD_SUCCESS;
+}
+
static int config_write_msc(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ struct bsc_context *bsc_ctx;
vty_out(vty, "msc%s", VTY_NEWLINE);
if (!gsmnet->auto_create_subscr)
@@ -127,6 +216,18 @@ static int config_write_msc(struct vty *vty)
mgcpgw_client_config_write(vty, " ");
iu_vty_config_write(vty, " ");
+ /* write sccp connection configuration */
+ llist_for_each_entry(bsc_ctx, &gsmnet->a.bscs, list) {
+ OSMO_ASSERT(bsc_ctx->ss7);
+ vty_out(vty,
+ " bsc cs7-instance %u calling-addr %s called-addr %s%s",
+ bsc_ctx->ss7->cfg.id,
+ osmo_sccp_name_by_addr(&bsc_ctx->calling_addr,
+ bsc_ctx->ss7),
+ osmo_sccp_name_by_addr(&bsc_ctx->called_addr,
+ bsc_ctx->ss7), VTY_NEWLINE);
+ }
+
return CMD_SUCCESS;
}
@@ -176,6 +277,9 @@ void msc_vty_init(struct gsm_network *msc_network)
install_element(MSC_NODE, &cfg_msc_no_subscr_create_cmd);
install_element(MSC_NODE, &cfg_msc_assign_tmsi_cmd);
install_element(MSC_NODE, &cfg_msc_no_assign_tmsi_cmd);
+ install_element(MSC_NODE, &cfg_msc_register_bsc_cmd);
+ install_element(MSC_NODE, &cfg_msc_no_register_bsc_cmd);
+
mgcpgw_client_vty_init(MSC_NODE, &msc_network->mgcpgw.conf);
iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc);
}