aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/lb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/lb.c')
-rw-r--r--src/osmo-bsc/lb.c386
1 files changed, 271 insertions, 115 deletions
diff --git a/src/osmo-bsc/lb.c b/src/osmo-bsc/lb.c
index 77fa1165b..6f3cfac7c 100644
--- a/src/osmo-bsc/lb.c
+++ b/src/osmo-bsc/lb.c
@@ -30,6 +30,7 @@
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/bsc/lcs_loc_req.h>
+#include <osmocom/bsc/bssmap_reset.h>
static struct gsm_subscriber_connection *get_bsc_conn_by_lb_conn_id(int conn_id)
{
@@ -45,8 +46,7 @@ static struct gsm_subscriber_connection *get_bsc_conn_by_lb_conn_id(int conn_id)
}
/* Send reset to SMLC */
-int bssmap_le_tx_reset()
- // TODO use this -- patch coming up
+int bssmap_le_tx_reset(void)
{
struct osmo_ss7_instance *ss7;
struct msgb *msg;
@@ -58,18 +58,23 @@ int bssmap_le_tx_reset()
},
};
- ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc.cs7_instance);
+ if (!bsc_gsmnet->smlc->sccp_user) {
+ LOGP(DRESET, LOGL_DEBUG, "Not sending RESET to SMLC, Lb link down\n");
+ return -1;
+ }
+
+ ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);
OSMO_ASSERT(ss7);
- LOGP(DLCS, LOGL_NOTICE, "Sending RESET to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc.smlc_addr));
+ LOGP(DRESET, LOGL_INFO, "Sending RESET to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));
msg = osmo_bssap_le_enc(&reset);
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET]);
- return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc.sccp_user, &bsc_gsmnet->smlc.bsc_addr,
- &bsc_gsmnet->smlc.smlc_addr, msg);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_UDT_RESET));
+ return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,
+ &bsc_gsmnet->smlc->smlc_addr, msg);
}
/* Send reset-ack to SMLC */
-int bssmap_le_tx_reset_ack()
+int bssmap_le_tx_reset_ack(void)
{
struct osmo_ss7_instance *ss7;
struct msgb *msg;
@@ -80,35 +85,14 @@ int bssmap_le_tx_reset_ack()
},
};
- ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc.cs7_instance);
+ ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);
OSMO_ASSERT(ss7);
- LOGP(DLCS, LOGL_NOTICE, "Tx RESET ACK to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc.smlc_addr));
+ LOGP(DRESET, LOGL_NOTICE, "Sending RESET ACK to SMLC: %s\n", osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));
msg = osmo_bssap_le_enc(&reset_ack);
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK]);
- return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc.sccp_user, &bsc_gsmnet->smlc.bsc_addr,
- &bsc_gsmnet->smlc.smlc_addr, msg);
-}
-
-static int bssmap_le_handle_reset(const struct bssmap_le_pdu *pdu)
-{
- struct gsm_subscriber_connection *conn;
- int rc;
-
- /* Abort all ongoing Location Requests */
- llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry)
- lcs_loc_req_reset(conn);
-
- rc = bssmap_le_tx_reset_ack();
- if (!rc)
- bsc_gsmnet->smlc.ready = true;
- return rc;
-}
-
-static int bssmap_le_handle_reset_ack()
-{
- bsc_gsmnet->smlc.ready = true;
- return 0;
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_UDT_RESET_ACK));
+ return osmo_sccp_tx_unitdata_msg(bsc_gsmnet->smlc->sccp_user, &bsc_gsmnet->smlc->bsc_addr,
+ &bsc_gsmnet->smlc->smlc_addr, msg);
}
static int handle_unitdata_from_smlc(const struct osmo_sccp_addr *smlc_addr, struct msgb *msg,
@@ -116,22 +100,22 @@ static int handle_unitdata_from_smlc(const struct osmo_sccp_addr *smlc_addr, str
{
struct osmo_ss7_instance *ss7;
struct bssap_le_pdu bssap_le;
- struct osmo_bssap_le_err *err;
- struct rate_ctr *ctr = bsc_gsmnet->smlc.ctrs->ctr;
+ struct osmo_bssap_le_err *err = NULL;
+ struct rate_ctr_group *ctrg = bsc_gsmnet->smlc->ctrs;
ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));
OSMO_ASSERT(ss7);
- if (osmo_sccp_addr_cmp(smlc_addr, &bsc_gsmnet->smlc.smlc_addr, OSMO_SCCP_ADDR_T_MASK)) {
+ if (osmo_sccp_addr_cmp(smlc_addr, &bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_ADDR_T_MASK)) {
LOGP(DLCS, LOGL_ERROR, "Rx BSSMAP-LE UnitData from unknown remote address: %s\n",
osmo_sccp_addr_name(ss7, smlc_addr));
- rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UNKNOWN_PEER));
return -EINVAL;
}
if (osmo_bssap_le_dec(&bssap_le, &err, msg, msg)) {
LOGP(DLCS, LOGL_ERROR, "Rx BSSAP-LE UnitData with error: %s\n", err->logmsg);
- rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG));
return -EINVAL;
}
@@ -142,15 +126,17 @@ static int handle_unitdata_from_smlc(const struct osmo_sccp_addr *smlc_addr, str
switch (bssap_le.bssmap_le.msg_type) {
case BSSMAP_LE_MSGT_RESET:
- rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_RESET));
LOGP(DLCS, LOGL_NOTICE, "RESET from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));
- return bssmap_le_handle_reset(&bssap_le.bssmap_le);
+ return osmo_fsm_inst_dispatch(bsc_gsmnet->smlc->bssmap_reset->fi, BSSMAP_RESET_EV_RX_RESET, NULL);
+
case BSSMAP_LE_MSGT_RESET_ACK:
- rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_RESET_ACK));
LOGP(DLCS, LOGL_NOTICE, "RESET-ACK from SMLC: %s\n", osmo_sccp_addr_name(ss7, smlc_addr));
- return bssmap_le_handle_reset_ack();
+ return osmo_fsm_inst_dispatch(bsc_gsmnet->smlc->bssmap_reset->fi, BSSMAP_RESET_EV_RX_RESET_ACK, NULL);
+
default:
- rate_ctr_inc(&ctr[SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, SMLC_CTR_BSSMAP_LE_RX_UDT_ERR_INVALID_MSG));
LOGP(DLCS, LOGL_ERROR, "Rx unimplemented UDT message type %s\n",
osmo_bssap_le_pdu_to_str_c(OTC_SELECT, &bssap_le));
return -EINVAL;
@@ -255,23 +241,23 @@ static int lb_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg
return -EINVAL;
}
- conn_id = bsc_sccp_inst_next_conn_id(bsc_gsmnet->smlc.sccp);
+ conn_id = bsc_sccp_inst_next_conn_id(bsc_gsmnet->smlc->sccp);
if (conn_id < 0) {
LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Unable to allocate SCCP Connection ID for BSSMAP-LE to SMLC\n");
return -ENOSPC;
}
conn->lcs.lb.conn_id = conn_id;
- ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc.cs7_instance);
+ ss7 = osmo_ss7_instance_find(bsc_gsmnet->smlc->cs7_instance);
OSMO_ASSERT(ss7);
LOGPFSMSL(conn->fi, DLCS, LOGL_INFO, "Opening new SCCP connection (id=%i) to SMLC: %s\n", conn_id,
- osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc.smlc_addr));
+ osmo_sccp_addr_name(ss7, &bsc_gsmnet->smlc->smlc_addr));
- rc = osmo_sccp_tx_conn_req_msg(bsc_gsmnet->smlc.sccp_user, conn_id, &bsc_gsmnet->smlc.bsc_addr,
- &bsc_gsmnet->smlc.smlc_addr, msg);
+ rc = osmo_sccp_tx_conn_req_msg(bsc_gsmnet->smlc->sccp_user, conn_id, &bsc_gsmnet->smlc->bsc_addr,
+ &bsc_gsmnet->smlc->smlc_addr, msg);
if (rc >= 0)
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_SUCCESS));
else
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_ERR_SEND));
if (rc >= 0)
conn->lcs.lb.state = SUBSCR_SCCP_ST_WAIT_CONN_CONF;
@@ -282,7 +268,7 @@ void lb_close_conn(struct gsm_subscriber_connection *conn)
{
if (conn->lcs.lb.state == SUBSCR_SCCP_ST_NONE)
return;
- osmo_sccp_tx_disconn(bsc_gsmnet->smlc.sccp_user, conn->lcs.lb.conn_id, &bsc_gsmnet->smlc.bsc_addr, 0);
+ osmo_sccp_tx_disconn(bsc_gsmnet->smlc->sccp_user, conn->lcs.lb.conn_id, &bsc_gsmnet->smlc->bsc_addr, 0);
conn->lcs.lb.state = SUBSCR_SCCP_ST_NONE;
}
@@ -294,6 +280,15 @@ int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *b
OSMO_ASSERT(conn);
+ if (!bssmap_reset_is_conn_ready(bsc_gsmnet->smlc->bssmap_reset)) {
+ LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Lb link to SMLC is not ready (no RESET-ACK), cannot send %s\n",
+ osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));
+ /* If the remote side was lost, make sure that the SCCP conn is discarded in the local state and towards
+ * the STP. */
+ lb_close_conn(conn);
+ return -EINVAL;
+ }
+
msg = osmo_bssap_le_enc(bssap_le);
if (!msg) {
LOGPFSMSL(conn->fi, DLCS, LOGL_ERROR, "Failed to encode %s\n",
@@ -307,11 +302,11 @@ int lb_send(struct gsm_subscriber_connection *conn, const struct bssap_le_pdu *b
}
LOGPFSMSL(conn->fi, DLCS, LOGL_DEBUG, "Tx %s\n", osmo_bssap_le_pdu_to_str_c(OTC_SELECT, bssap_le));
- rc = osmo_sccp_tx_data_msg(bsc_gsmnet->smlc.sccp_user, conn->lcs.lb.conn_id, msg);
+ rc = osmo_sccp_tx_data_msg(bsc_gsmnet->smlc->sccp_user, conn->lcs.lb.conn_id, msg);
if (rc >= 0)
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_SUCCESS]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_SUCCESS));
else
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_ERR_SEND]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_ERR_SEND));
count_tx:
if (rc < 0)
@@ -319,24 +314,24 @@ count_tx:
switch (bssap_le->bssmap_le.msg_type) {
case BSSMAP_LE_MSGT_PERFORM_LOC_REQ:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_REQUEST));
break;
case BSSMAP_LE_MSGT_PERFORM_LOC_ABORT:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_PERFORM_LOCATION_ABORT));
break;
case BSSMAP_LE_MSGT_CONN_ORIENTED_INFO:
switch (bssap_le->bssmap_le.conn_oriented_info.apdu.msg_type) {
case BSSLAP_MSGT_TA_RESPONSE:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_TA_RESPONSE));
break;
case BSSLAP_MSGT_REJECT:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_REJECT));
break;
case BSSLAP_MSGT_RESET:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_RESET));
break;
case BSSLAP_MSGT_ABORT:
- rate_ctr_inc(&bsc_gsmnet->smlc.ctrs->ctr[SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->smlc->ctrs, SMLC_CTR_BSSMAP_LE_TX_DT1_BSSLAP_ABORT));
break;
default:
break;
@@ -357,8 +352,65 @@ count_tx:
#define DEFAULT_ASP_LOCAL_IP "localhost"
#define DEFAULT_ASP_REMOTE_IP "localhost"
-/* Initialize Lb interface to SMLC */
-int lb_init()
+void lb_cancel_all(void)
+{
+ struct gsm_subscriber_connection *conn;
+ llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry)
+ lcs_loc_req_reset(conn);
+};
+
+void lb_reset_link_up(void *data)
+{
+ LOGP(DLCS, LOGL_INFO, "Lb link ready\n");
+}
+
+void lb_reset_link_lost(void *data)
+{
+ struct gsm_subscriber_connection *conn;
+ LOGP(DLCS, LOGL_INFO, "Lb link down\n");
+
+ /* Abort all ongoing Location Requests */
+ llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry)
+ lcs_loc_req_reset(conn);
+};
+
+void lb_reset_tx_reset(void *data)
+{
+ bssmap_le_tx_reset();
+}
+
+void lb_reset_tx_reset_ack(void *data)
+{
+ bssmap_le_tx_reset_ack();
+}
+
+static void lb_start_reset_fsm(void)
+{
+ struct bssmap_reset_cfg cfg = {
+ .conn_cfm_failure_threshold = 3,
+ .ops = {
+ .tx_reset = lb_reset_tx_reset,
+ .tx_reset_ack = lb_reset_tx_reset_ack,
+ .link_up = lb_reset_link_up,
+ .link_lost = lb_reset_link_lost,
+ },
+ };
+
+ if (bsc_gsmnet->smlc->bssmap_reset) {
+ LOGP(DLCS, LOGL_ERROR, "will not allocate a second reset FSM for Lb\n");
+ return;
+ }
+
+ bsc_gsmnet->smlc->bssmap_reset = bssmap_reset_alloc(bsc_gsmnet, "Lb", &cfg);
+}
+
+static void lb_stop_reset_fsm(void)
+{
+ bssmap_reset_term_and_free(bsc_gsmnet->smlc->bssmap_reset);
+ bsc_gsmnet->smlc->bssmap_reset = NULL;
+}
+
+static int lb_start(void)
{
uint32_t default_pc;
struct osmo_ss7_instance *cs7_inst = NULL;
@@ -367,15 +419,21 @@ int lb_init()
char inst_name[32];
const char *smlc_name = "smlc";
- if (!bsc_gsmnet->smlc.cs7_instance_valid) {
- bsc_gsmnet->smlc.cs7_instance = 0;
+ /* Already set up? */
+ if (bsc_gsmnet->smlc->sccp_user)
+ return -EALREADY;
+
+ LOGP(DLCS, LOGL_INFO, "Starting Lb link\n");
+
+ if (!bsc_gsmnet->smlc->cs7_instance_valid) {
+ bsc_gsmnet->smlc->cs7_instance = 0;
}
- cs7_inst = osmo_ss7_instance_find_or_create(tall_bsc_ctx, bsc_gsmnet->smlc.cs7_instance);
+ cs7_inst = osmo_ss7_instance_find_or_create(tall_bsc_ctx, bsc_gsmnet->smlc->cs7_instance);
OSMO_ASSERT(cs7_inst);
/* If unset, use default SCCP address for the SMLC */
- if (!bsc_gsmnet->smlc.smlc_addr.presence)
- osmo_sccp_make_addr_pc_ssn(&bsc_gsmnet->smlc.smlc_addr,
+ if (!bsc_gsmnet->smlc->smlc_addr.presence)
+ osmo_sccp_make_addr_pc_ssn(&bsc_gsmnet->smlc->smlc_addr,
osmo_ss7_pointcode_parse(NULL, SMLC_DEFAULT_PC),
OSMO_SCCP_SSN_SMLC_BSSAP_LE);
@@ -392,41 +450,98 @@ int lb_init()
0, DEFAULT_ASP_REMOTE_IP);
if (!sccp)
return -EINVAL;
- bsc_gsmnet->smlc.sccp = sccp;
+ bsc_gsmnet->smlc->sccp = sccp;
/* If unset, use default local SCCP address */
- if (!bsc_gsmnet->smlc.bsc_addr.presence)
- osmo_sccp_local_addr_by_instance(&bsc_gsmnet->smlc.bsc_addr, sccp,
+ if (!bsc_gsmnet->smlc->bsc_addr.presence)
+ osmo_sccp_local_addr_by_instance(&bsc_gsmnet->smlc->bsc_addr, sccp,
OSMO_SCCP_SSN_BSC_BSSAP_LE);
- if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc.bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
+ if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc->bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
LOGP(DLCS, LOGL_ERROR,
"%s %s: invalid local (BSC) SCCP address: %s\n",
- inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc.bsc_addr));
+ inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->bsc_addr));
return -EINVAL;
}
- if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc.smlc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
+ if (!osmo_sccp_check_addr(&bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
LOGP(DLCS, LOGL_ERROR,
"%s %s: invalid remote (SMLC) SCCP address: %s\n",
- inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc.smlc_addr));
+ inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->smlc_addr));
return -EINVAL;
}
LOGP(DLCS, LOGL_NOTICE, "Lb: %s %s: local (BSC) SCCP address: %s\n",
- inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc.bsc_addr));
+ inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->bsc_addr));
LOGP(DLCS, LOGL_NOTICE, "Lb: %s %s: remote (SMLC) SCCP address: %s\n",
- inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc.smlc_addr));
-
- /* Bind SCCP user. */
- bsc_gsmnet->smlc.sccp_user = osmo_sccp_user_find(sccp, bsc_gsmnet->smlc.bsc_addr.ssn, bsc_gsmnet->smlc.bsc_addr.pc);
- LOGP(DLCS, LOGL_NOTICE, "%s %s: %s\n", inst_name, smlc_name,
- bsc_gsmnet->smlc.sccp_user ? "user already bound for this SCCP instance" : "binding SCCP user");
- if (!bsc_gsmnet->smlc.sccp_user)
- bsc_gsmnet->smlc.sccp_user = osmo_sccp_user_bind(sccp, smlc_name, sccp_sap_up, bsc_gsmnet->smlc.bsc_addr.ssn);
- if (!bsc_gsmnet->smlc.sccp_user)
+ inst_name, smlc_name, osmo_sccp_inst_addr_name(sccp, &bsc_gsmnet->smlc->smlc_addr));
+
+ bsc_gsmnet->smlc->sccp_user = osmo_sccp_user_bind(sccp, smlc_name, sccp_sap_up, bsc_gsmnet->smlc->bsc_addr.ssn);
+ if (!bsc_gsmnet->smlc->sccp_user)
return -EINVAL;
+ lb_start_reset_fsm();
+ return 0;
+}
+
+static int lb_stop(void)
+{
+ /* Not set up? */
+ if (!bsc_gsmnet->smlc->sccp_user)
+ return -EALREADY;
+
+ LOGP(DLCS, LOGL_INFO, "Shutting down Lb link\n");
+
+ lb_cancel_all();
+ lb_stop_reset_fsm();
+ osmo_sccp_user_unbind(bsc_gsmnet->smlc->sccp_user);
+ bsc_gsmnet->smlc->sccp_user = NULL;
+ return 0;
+}
+
+int lb_start_or_stop(void)
+{
+ int rc;
+ if (bsc_gsmnet->smlc->enable) {
+ rc = lb_start();
+ switch (rc) {
+ case 0:
+ /* all is fine */
+ break;
+ case -EALREADY:
+ /* no need to log about anything */
+ break;
+ default:
+ LOGP(DLCS, LOGL_ERROR, "Failed to start Lb interface (rc=%d)\n", rc);
+ break;
+ }
+ } else {
+ rc = lb_stop();
+ switch (rc) {
+ case 0:
+ /* all is fine */
+ break;
+ case -EALREADY:
+ /* no need to log about anything */
+ break;
+ default:
+ LOGP(DLCS, LOGL_ERROR, "Failed to stop Lb interface (rc=%d)\n", rc);
+ break;
+ }
+ }
+ return rc;
+}
+
+static void smlc_vty_init(void);
+
+int lb_init(void)
+{
+ OSMO_ASSERT(!bsc_gsmnet->smlc);
+ bsc_gsmnet->smlc = talloc_zero(bsc_gsmnet, struct smlc_config);
+ OSMO_ASSERT(bsc_gsmnet->smlc);
+ bsc_gsmnet->smlc->ctrs = rate_ctr_group_alloc(bsc_gsmnet, &smlc_ctrg_desc, 0);
+
+ smlc_vty_init();
return 0;
}
@@ -447,6 +562,30 @@ static struct cmd_node smlc_node = {
1,
};
+DEFUN(cfg_smlc_enable, cfg_smlc_enable_cmd,
+ "enable",
+ "Start up Lb interface connection to the remote SMLC\n")
+{
+ bsc_gsmnet->smlc->enable = true;
+ if (vty->type != VTY_FILE) {
+ if (lb_start_or_stop())
+ vty_out(vty, "%% Error: failed to enable Lb interface%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_smlc_no_enable, cfg_smlc_no_enable_cmd,
+ "no enable",
+ NO_STR "Stop Lb interface connection to the remote SMLC\n")
+{
+ bsc_gsmnet->smlc->enable = false;
+ if (vty->type != VTY_FILE) {
+ if (lb_start_or_stop())
+ vty_out(vty, "%% Error: failed to disable Lb interface%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
static void enforce_ssn(struct vty *vty, struct osmo_sccp_addr *addr, enum osmo_sccp_ssn want_ssn)
{
if (addr->presence & OSMO_SCCP_ADDR_T_SSN) {
@@ -460,6 +599,28 @@ static void enforce_ssn(struct vty *vty, struct osmo_sccp_addr *addr, enum osmo_
addr->ssn = want_ssn;
}
+/* Prevent mixing addresses from different CS7 instances */
+bool smlc_set_cs7_instance(struct vty *vty, const char *from_vty_cmd, const char *from_addr,
+ struct osmo_ss7_instance *ss7)
+{
+ if (bsc_gsmnet->smlc->cs7_instance_valid) {
+ if (bsc_gsmnet->smlc->cs7_instance != ss7->cfg.id) {
+ LOGP(DLCS, LOGL_ERROR,
+ "%s: expecting address from cs7 instance %u, but '%s' is from %u\n",
+ from_vty_cmd, bsc_gsmnet->smlc->cs7_instance, from_addr, ss7->cfg.id);
+ vty_out(vty, "Error:"
+ " %s: expecting address from cs7 instance %u, but '%s' is from %u%s",
+ from_vty_cmd, bsc_gsmnet->smlc->cs7_instance, from_addr, ss7->cfg.id, VTY_NEWLINE);
+ return false;
+ }
+ } else {
+ bsc_gsmnet->smlc->cs7_instance = ss7->cfg.id;
+ bsc_gsmnet->smlc->cs7_instance_valid = true;
+ LOGP(DLCS, LOGL_NOTICE, "Lb interface is using cs7 instance %u\n", bsc_gsmnet->smlc->cs7_instance);
+ }
+ return true;
+}
+
DEFUN(cfg_smlc_cs7_bsc_addr,
cfg_smlc_cs7_bsc_addr_cmd,
"bsc-addr NAME",
@@ -468,25 +629,17 @@ DEFUN(cfg_smlc_cs7_bsc_addr,
const char *bsc_addr_name = argv[0];
struct osmo_ss7_instance *ss7;
- ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc.bsc_addr, bsc_addr_name);
+ ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc->bsc_addr, bsc_addr_name);
if (!ss7) {
vty_out(vty, "Error: No such SCCP addressbook entry: '%s'%s", bsc_addr_name, VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
- /* Prevent mixing addresses from different CS7 instances */
- if (bsc_gsmnet->smlc.cs7_instance_valid
- && bsc_gsmnet->smlc.cs7_instance != ss7->cfg.id) {
- vty_out(vty,
- "Error: SCCP addressbook entry from mismatching CS7 instance: '%s'%s",
- bsc_addr_name, VTY_NEWLINE);
+ if (!smlc_set_cs7_instance(vty, "smlc / bsc-addr", bsc_addr_name, ss7))
return CMD_WARNING;
- }
- bsc_gsmnet->smlc.cs7_instance = ss7->cfg.id;
- bsc_gsmnet->smlc.cs7_instance_valid = true;
- enforce_ssn(vty, &bsc_gsmnet->smlc.bsc_addr, OSMO_SCCP_SSN_BSC_BSSAP_LE);
- bsc_gsmnet->smlc.bsc_addr_name = talloc_strdup(bsc_gsmnet, bsc_addr_name);
+ enforce_ssn(vty, &bsc_gsmnet->smlc->bsc_addr, OSMO_SCCP_SSN_BSC_BSSAP_LE);
+ bsc_gsmnet->smlc->bsc_addr_name = talloc_strdup(bsc_gsmnet, bsc_addr_name);
return CMD_SUCCESS;
}
@@ -498,39 +651,40 @@ DEFUN(cfg_smlc_cs7_smlc_addr,
const char *smlc_addr_name = argv[0];
struct osmo_ss7_instance *ss7;
- ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc.smlc_addr, smlc_addr_name);
+ ss7 = osmo_sccp_addr_by_name(&bsc_gsmnet->smlc->smlc_addr, smlc_addr_name);
if (!ss7) {
vty_out(vty, "Error: No such SCCP addressbook entry: '%s'%s", smlc_addr_name, VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
- /* Prevent mixing addresses from different CS7/SS7 instances */
- if (bsc_gsmnet->smlc.cs7_instance_valid) {
- if (bsc_gsmnet->smlc.cs7_instance != ss7->cfg.id) {
- vty_out(vty,
- "Error: SCCP addressbook entry from mismatching CS7 instance: '%s'%s",
- smlc_addr_name, VTY_NEWLINE);
- return CMD_ERR_INCOMPLETE;
- }
- }
+ if (!smlc_set_cs7_instance(vty, "smlc / smlc-addr", smlc_addr_name, ss7))
+ return CMD_WARNING;
- bsc_gsmnet->smlc.cs7_instance = ss7->cfg.id;
- bsc_gsmnet->smlc.cs7_instance_valid = true;
- enforce_ssn(vty, &bsc_gsmnet->smlc.smlc_addr, OSMO_SCCP_SSN_SMLC_BSSAP_LE);
- bsc_gsmnet->smlc.smlc_addr_name = talloc_strdup(bsc_gsmnet, smlc_addr_name);
+ enforce_ssn(vty, &bsc_gsmnet->smlc->smlc_addr, OSMO_SCCP_SSN_SMLC_BSSAP_LE);
+ bsc_gsmnet->smlc->smlc_addr_name = talloc_strdup(bsc_gsmnet, smlc_addr_name);
return CMD_SUCCESS;
}
static int config_write_smlc(struct vty *vty)
{
+ /* Nothing to write? */
+ if (!(bsc_gsmnet->smlc->enable
+ || bsc_gsmnet->smlc->bsc_addr_name
+ || bsc_gsmnet->smlc->smlc_addr_name))
+ return 0;
+
vty_out(vty, "smlc%s", VTY_NEWLINE);
- if (bsc_gsmnet->smlc.bsc_addr_name) {
+
+ if (bsc_gsmnet->smlc->enable)
+ vty_out(vty, " enable%s", VTY_NEWLINE);
+
+ if (bsc_gsmnet->smlc->bsc_addr_name) {
vty_out(vty, " bsc-addr %s%s",
- bsc_gsmnet->smlc.bsc_addr_name, VTY_NEWLINE);
+ bsc_gsmnet->smlc->bsc_addr_name, VTY_NEWLINE);
}
- if (bsc_gsmnet->smlc.smlc_addr_name) {
+ if (bsc_gsmnet->smlc->smlc_addr_name) {
vty_out(vty, " smlc-addr %s%s",
- bsc_gsmnet->smlc.smlc_addr_name, VTY_NEWLINE);
+ bsc_gsmnet->smlc->smlc_addr_name, VTY_NEWLINE);
}
return 0;
@@ -550,6 +704,8 @@ void smlc_vty_init(void)
install_element(CONFIG_NODE, &cfg_smlc_cmd);
install_node(&smlc_node, config_write_smlc);
+ install_element(SMLC_NODE, &cfg_smlc_enable_cmd);
+ install_element(SMLC_NODE, &cfg_smlc_no_enable_cmd);
install_element(SMLC_NODE, &cfg_smlc_cs7_bsc_addr_cmd);
install_element(SMLC_NODE, &cfg_smlc_cs7_smlc_addr_cmd);
}