aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmsc/a_iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libmsc/a_iface.c')
-rw-r--r--openbsc/src/libmsc/a_iface.c131
1 files changed, 87 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;
+ }
+ }
+}