diff options
Diffstat (limited to 'src/osmo-bsc/lb.c')
-rw-r--r-- | src/osmo-bsc/lb.c | 386 |
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); } |