aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill Zakharenko <earwin@gmail.com>2020-05-08 23:55:58 +0300
committerKirill Zakharenko <earwin@gmail.com>2020-05-08 23:55:58 +0300
commit5d7b1ef2868024ff43cd9c729c6b5b0fd86fd80e (patch)
treeea947d8fc4aef3fcdc3f1a315a79c3deeb4a9887
parentf5bbe0880ec1c6883ab1f9e8727aec348f51abdf (diff)
parentf103cd38665618442196de888b1e4390fb256ddb (diff)
Merge fairwaves/WIP-dyn-chan-load into fairwaves/production
-rw-r--r--include/osmocom/bsc/bsc_msc_data.h27
-rw-r--r--include/osmocom/bsc/gsm_data.h20
-rw-r--r--src/osmo-bsc/a_reset.c41
-rw-r--r--src/osmo-bsc/abis_om2000.c289
-rw-r--r--src/osmo-bsc/abis_om2000_vty.c43
-rw-r--r--src/osmo-bsc/bsc_init.c9
-rw-r--r--src/osmo-bsc/bsc_vty.c1
-rw-r--r--src/osmo-bsc/bts_ericsson_rbs2000.c14
-rw-r--r--src/osmo-bsc/bts_ipaccess_nanobts.c12
-rw-r--r--src/osmo-bsc/bts_nokia_site.c55
-rw-r--r--src/osmo-bsc/chan_alloc.c30
-rw-r--r--src/osmo-bsc/gsm_data.c40
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c27
-rw-r--r--src/osmo-bsc/osmo_bsc_msc.c50
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c6
15 files changed, 533 insertions, 131 deletions
diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h
index b9df4ba8f..dc9628bd1 100644
--- a/include/osmocom/bsc/bsc_msc_data.h
+++ b/include/osmocom/bsc/bsc_msc_data.h
@@ -56,6 +56,29 @@ enum {
MSC_CON_TYPE_LOCAL,
};
+/* Constants for the MSC rate counters */
+enum {
+ MSC_CTR_BSSMAP_RX_UDT_RESET_ACKNOWLEDGE,
+ MSC_CTR_BSSMAP_RX_UDT_RESET,
+ MSC_CTR_BSSMAP_RX_UDT_PAGING,
+ MSC_CTR_BSSMAP_RX_UDT_UNKNOWN,
+ MSC_CTR_BSSMAP_RX_DT1_CLEAR_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_CIPHER_MODE_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_ASSIGMENT_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_LCLS_CONNECT_CTRL,
+ MSC_CTR_BSSMAP_RX_DT1_HANDOVER_CMD,
+ MSC_CTR_BSSMAP_RX_DT1_CLASSMARK_RQST,
+ MSC_CTR_BSSMAP_RX_DT1_UNKNOWN,
+ MSC_CTR_BSSMAP_RX_DTAP_MSG,
+ MSC_CTR_BSSMAP_RX_DTAP_ERROR,
+};
+
+/* Constants for the MSC stats */
+enum {
+ MSC_STAT_MSC_LINKS_ACTIVE,
+ MSC_STAT_MSC_LINKS_TOTAL,
+};
+
/*! /brief Information on a remote MSC for libbsc.
*/
struct bsc_msc_data {
@@ -99,6 +122,10 @@ struct bsc_msc_data {
char *acc_lst_name;
+ /* structures for keeping rate counters and gauge stats */
+ struct rate_ctr_group *msc_ctrs;
+ struct osmo_stat_item_group *msc_statg;
+
/* Sigtran connection data */
struct {
uint32_t cs7_instance;
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 9a8e002ea..5e4b532c5 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -1134,7 +1134,15 @@ struct gsm_bts {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
} tf;
+ struct {
+ struct om2k_mo om2k_mo;
+ struct gsm_abis_mo mo;
+ } mctr;
uint32_t use_superchannel:1;
+ struct {
+ uint16_t limit;
+ uint16_t active;
+ } om2k_version[16];
} rbs2000;
struct {
uint8_t bts_type;
@@ -1143,7 +1151,7 @@ struct gsm_bts {
no_loc_rel_cnf:1, /* don't wait for RSL REL CONF */
bts_reset_timer_cnf, /* timer for BTS RESET */
did_reset:1, /* we received a RESET ACK */
- wait_reset:1; /* we are waiting for reset to complete */
+ wait_reset:2; /* we are waiting for reset to complete */
struct osmo_timer_list reset_timer;
} nokia;
};
@@ -1464,8 +1472,8 @@ enum {
BTS_STAT_T3122,
BTS_STAT_RACH_BUSY,
BTS_STAT_RACH_ACCESS,
- BTS_STAT_NUM_OML_CONNECTED,
- BTS_STAT_NUM_RSL_CONNECTED,
+ BTS_STAT_OML_CONNECTED,
+ BTS_STAT_RSL_CONNECTED,
};
enum {
@@ -1556,10 +1564,9 @@ static const struct rate_ctr_group_desc bsc_ctrg_desc = {
bsc_ctr_description,
};
+/* Constants for the BSC stats */
enum {
- BSC_STAT_MSC_LINK,
- BSC_STAT_NUM_BTS_CONNECTED,
- BSC_STAT_NUM_TRX_CONNECTED,
+ BSC_STAT_NUM_BTS_TOTAL,
};
struct gsm_tz {
@@ -1588,6 +1595,7 @@ struct gsm_network {
struct osmo_timer_list congestion_check_timer;
} hodec2;
+ /* structures for keeping rate counters and gauge stats */
struct rate_ctr_group *bsc_ctrs;
struct osmo_stat_item_group *bsc_statg;
diff --git a/src/osmo-bsc/a_reset.c b/src/osmo-bsc/a_reset.c
index 9d7be8585..63273e9f2 100644
--- a/src/osmo-bsc/a_reset.c
+++ b/src/osmo-bsc/a_reset.c
@@ -66,20 +66,28 @@ static const struct value_string fsm_event_names[] = {
{0, NULL}
};
-/* Disconnected state */
+/* Disconnected state event handler */
static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
OSMO_ASSERT(reset_ctx);
- struct bsc_msc_data *msc = reset_ctx->priv;
- LOGPFSML(fi, LOGL_NOTICE, "SIGTRAN connection succeeded.\n");
- osmo_stat_item_set(msc->network->bsc_statg->items[BSC_STAT_MSC_LINK], 1);
reset_ctx->conn_loss_counter = 0;
osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0);
}
-/* Connected state */
+/* Called when entering Disconnected state */
+static void fsm_disc_onenter_cb(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
+ struct bsc_msc_data *msc = reset_ctx->priv;
+
+ LOGPFSML(fi, LOGL_NOTICE, "SIGTRAN connection down, reconnecting...\n");
+ if (prev_state != ST_DISC)
+ osmo_stat_item_dec(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);
+}
+
+/* Connected state event handler */
static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
@@ -87,12 +95,9 @@ static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
switch (event) {
case EV_N_DISCONNECT:
- if (reset_ctx->conn_loss_counter >= BAD_CONNECTION_THRESOLD) {
- struct bsc_msc_data *msc = reset_ctx->priv;
- LOGPFSML(fi, LOGL_NOTICE, "SIGTRAN connection down, reconnecting...\n");
- osmo_stat_item_set(msc->network->bsc_statg->items[BSC_STAT_MSC_LINK], 0);
+ if (reset_ctx->conn_loss_counter >= BAD_CONNECTION_THRESOLD)
osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO);
- } else
+ else
reset_ctx->conn_loss_counter++;
break;
case EV_N_CONNECT:
@@ -101,6 +106,17 @@ static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
+/* Called when entering Connected state */
+static void fsm_conn_onenter_cb(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct reset_ctx *reset_ctx = (struct reset_ctx *)fi->priv;
+ struct bsc_msc_data *msc = reset_ctx->priv;
+
+ LOGPFSML(fi, LOGL_NOTICE, "SIGTRAN connection succeeded.\n");
+ if (prev_state != ST_CONN)
+ osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_ACTIVE], 1);
+}
+
/* Timer callback to retransmit the reset signal */
static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi)
{
@@ -121,12 +137,14 @@ static struct osmo_fsm_state reset_fsm_states[] = {
.out_state_mask = (1 << ST_DISC) | (1 << ST_CONN),
.name = "DISC",
.action = fsm_disc_cb,
+ .onenter = fsm_disc_onenter_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,
+ .onenter = fsm_conn_onenter_cb,
},
};
@@ -165,6 +183,9 @@ void a_reset_alloc(struct bsc_msc_data *msc, const char *name, void *cb)
/* Immediately (1ms) kick off reset sending mechanism */
osmo_fsm_inst_state_chg_ms(reset_fsm, ST_DISC, 1, RESET_RESEND_TIMER_NO);
+
+ /* Count the new MSC link */
+ osmo_stat_item_inc(msc->msc_statg->items[MSC_STAT_MSC_LINKS_TOTAL], 1);
}
/* Confirm that we successfully received a reset acknowledge message */
diff --git a/src/osmo-bsc/abis_om2000.c b/src/osmo-bsc/abis_om2000.c
index c32a5fa9a..c69655732 100644
--- a/src/osmo-bsc/abis_om2000.c
+++ b/src/osmo-bsc/abis_om2000.c
@@ -30,6 +30,7 @@
#include <arpa/inet.h>
+#include <osmocom/core/byteswap.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/talloc.h>
@@ -75,6 +76,7 @@ struct osmo_fsm_inst *osmo_fsm_inst_alloc_child_id(struct osmo_fsm *fsm,
#define OM_HEADROOM_SIZE 128
#define OM2K_TIMEOUT 10
+#define TRX_LAPD_TIMEOUT 5
#define TRX_FSM_TIMEOUT 60
#define BTS_FSM_TIMEOUT 60
@@ -219,13 +221,17 @@ enum abis_om2k_msgtype {
OM2K_MSGT_FEATURE_CTRL_COMPL = 0x011a,
OM2K_MSGT_FEATURE_CTRL_REJ = 0x011b,
- OM2K_MSGT_MCTR_CONFIG_REQ = 0x012c,
- OM2K_MSGT_MCTR_CONFIG_REQ_ACK = 0x012e,
- OM2K_MSGT_MCTR_CONFIG_REQ_REJ = 0x012f,
+ OM2K_MSGT_MCTR_CONF_REQ = 0x012c,
+ OM2K_MSGT_MCTR_CONF_REQ_ACK = 0x012e,
+ OM2K_MSGT_MCTR_CONF_REQ_REJ = 0x012f,
- OM2K_MSGT_MCTR_CONFIG_RES_ACK = 0x0130,
- OM2K_MSGT_MCTR_CONFIG_RES_NACK = 0x0131,
- OM2K_MSGT_MCTR_CONFIG_RES = 0x0132,
+ OM2K_MSGT_MCTR_CONF_RES_ACK = 0x0130,
+ OM2K_MSGT_MCTR_CONF_RES_NACK = 0x0131,
+ OM2K_MSGT_MCTR_CONF_RES = 0x0132,
+
+ OM2K_MSGT_MCTR_STATS_REP_ACK = 0x0134,
+ OM2K_MSGT_MCTR_STATS_REP_NACK = 0x0135,
+ OM2K_MSGT_MCTR_STATS_REP = 0x0136,
};
enum abis_om2k_dei {
@@ -305,6 +311,13 @@ enum abis_om2k_dei {
OM2K_DEI_MCTR_FEAT_STATUS_BMAP = 0xab,
};
+enum abis_om2k_mostate {
+ OM2K_MOSTATE_RESET = 0x00,
+ OM2K_MOSTATE_STARTED = 0x01,
+ OM2K_MOSTATE_ENABLED = 0x02,
+ OM2K_MOSTATE_DISABLED = 0x03,
+};
+
const struct tlv_definition om2k_att_tlvdef = {
.def = {
[OM2K_DEI_ACCORDANCE_IND] = { TLV_TYPE_TV },
@@ -558,6 +571,9 @@ static const struct value_string om2k_msgcode_vals[] = {
{ 0x0130, "MCTR Configuration Result ACK" },
{ 0x0131, "MCTR Configuration Result NACK" },
{ 0x0132, "MCTR Configuration Result" },
+ { 0x0134, "MCTR Statistics report ACK" },
+ { 0x0135, "MCTR Statistics report NACK" },
+ { 0x0136, "MCTR Statistics report" },
{ 0, NULL }
};
@@ -771,7 +787,9 @@ get_om2k_mo(struct gsm_bts *bts, const struct abis_om2k_mo *abis_mo)
case OM2K_MO_CLS_TF:
mo = &bts->rbs2000.tf.om2k_mo;
break;
-
+ case OM2K_MO_CLS_MCTR:
+ mo = &bts->rbs2000.mctr.om2k_mo;
+ break;
case OM2K_MO_CLS_TRXC:
trx = gsm_bts_trx_num(bts, abis_mo->inst);
if (!trx)
@@ -863,6 +881,9 @@ mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
return NULL;
nm_state = &trx->ts[mo->inst].mo.nm_state;
break;
+ case OM2K_MO_CLS_MCTR:
+ nm_state = &bts->rbs2000.mctr.mo.nm_state;
+ break;
case OM2K_MO_CLS_TF:
nm_state = &bts->rbs2000.tf.mo.nm_state;
break;
@@ -911,6 +932,7 @@ static void *mo2obj(struct gsm_bts *bts, struct abis_om2k_mo *mo)
if (mo->inst >= ARRAY_SIZE(trx->ts))
return NULL;
return &trx->ts[mo->inst];
+ case OM2K_MO_CLS_MCTR:
case OM2K_MO_CLS_TF:
case OM2K_MO_CLS_IS:
case OM2K_MO_CLS_CON:
@@ -928,13 +950,39 @@ static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo,
struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
struct gsm_nm_state new_state;
struct nm_statechg_signal_data nsd;
+ bool has_enabled_state;
if (!nm_state)
return;
+ switch (mo->class) {
+ case OM2K_MO_CLS_CF:
+ case OM2K_MO_CLS_TRXC:
+ has_enabled_state = false;
+ break;
+ default:
+ has_enabled_state = true;
+ break;
+ }
+
new_state = *nm_state;
- /* NOTICE: 12.21 Availability state values != OM2000 */
- new_state.availability = mo_state;
+ switch (mo_state) {
+ case OM2K_MOSTATE_RESET:
+ new_state.availability = NM_AVSTATE_POWER_OFF;
+ break;
+ case OM2K_MOSTATE_STARTED:
+ new_state.availability = has_enabled_state ? NM_AVSTATE_OFF_LINE : NM_AVSTATE_OK;
+ break;
+ case OM2K_MOSTATE_ENABLED:
+ new_state.availability = NM_AVSTATE_OK;
+ break;
+ case OM2K_MOSTATE_DISABLED:
+ new_state.availability = NM_AVSTATE_POWER_OFF;
+ break;
+ default:
+ new_state.availability = NM_AVSTATE_DEGRADED;
+ break;
+ }
memset(&nsd, 0, sizeof(nsd));
@@ -1247,6 +1295,35 @@ int abis_om2k_tx_con_conf_req(struct gsm_bts *bts)
return abis_om2k_sendmsg(bts, msg);
}
+int abis_om2k_tx_mctr_conf_req(struct gsm_bts *bts)
+{
+ struct msgb *msg = om2k_msgb_alloc();
+ struct abis_om2k_hdr *o2k;
+ struct gsm_bts_trx *trx;
+ uint8_t trxc_list = 0;
+ const uint8_t features[] = { 0x00 };
+
+ /* build trxc list */
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ trxc_list |= (1 << trx->nr);
+
+ /* fill message */
+ msgb_tv16_put(msg, OM2K_DEI_TRXC_LIST, osmo_swab16(trxc_list)); /* Read as LE by the BTS ... */
+ msgb_tv_put (msg, OM2K_DEI_MAX_ALLOWED_POWER, 0x31);
+ msgb_tv_put (msg, OM2K_DEI_MAX_ALLOWED_NUM_TRXCS, 0x08);
+ msgb_tlv_put (msg, OM2K_DEI_MCTR_FEAT_STATUS_BMAP, 1, features);
+
+ /* pre-pend the OM2K header */
+ o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k));
+ fill_om2k_hdr(o2k, &bts->rbs2000.mctr.om2k_mo.addr,
+ OM2K_MSGT_MCTR_CONF_REQ);
+ DEBUGP(DNM, "Tx MO=%s %s\n",
+ om2k_mo_name(&bts->rbs2000.mctr.om2k_mo.addr),
+ get_value_string(om2k_msgcode_vals, OM2K_MSGT_MCTR_CONF_REQ));
+
+ return abis_om2k_sendmsg(bts, msg);
+}
+
static void om2k_trx_to_mo(struct abis_om2k_mo *mo,
const struct gsm_bts_trx *trx,
enum abis_om2k_mo_cls cls)
@@ -1278,7 +1355,8 @@ int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx)
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, &mo, OM2K_MSGT_RX_CONF_REQ);
- msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, trx->arfcn);
+ /* OM2K_DEI_FREQ_SPEC_RX: Using trx_nr as "RX address" only works for single MCTR case */
+ msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, 0x8000 | ((uint16_t)trx->nr << 10));
msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */
return abis_om2k_sendmsg(trx->bts, msg);
@@ -1296,9 +1374,10 @@ int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx)
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TX_CONF_REQ);
- msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_TX, trx->arfcn);
+ /* OM2K_DEI_FREQ_SPEC_TX: Using trx_nr as "TX address" only works for single MCTR case */
+ msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_TX, trx->arfcn | ((uint16_t)trx->nr << 10));
msgb_tv_put(msg, OM2K_DEI_POWER, trx->nominal_power-trx->max_power_red);
- msgb_tv_put(msg, OM2K_DEI_FILLING_MARKER, 0); /* Filling enabled */
+ msgb_tv_put(msg, OM2K_DEI_FILLING_MARKER, trx != trx->bts->c0); /* Filling enabled for C0 only */
msgb_tv_put(msg, OM2K_DEI_BCC, trx->bts->bsic & 0x7);
/* Dedication Information is optional */
@@ -1368,15 +1447,44 @@ static uint8_t ts2comb(struct gsm_bts_trx_ts *ts)
* message for it. Rather fail completely right now: */
return 0;
}
- return pchan2comb(ts->pchan_is);
+ return pchan2comb(ts->pchan_from_config);
}
-static int put_freq_list(uint8_t *buf, uint16_t arfcn)
+static int put_freq_list(uint8_t *buf, struct gsm_bts_trx_ts *ts, uint16_t arfcn)
{
- buf[0] = 0x00; /* TX/RX address */
+ struct gsm_bts_trx *trx;
+
+ /* Find the TRX that's configured for that ARFCN */
+ llist_for_each_entry(trx, &ts->trx->bts->trx_list, list)
+ if (trx->arfcn == arfcn)
+ break;
+
+ if (!trx || (trx->arfcn != arfcn)) {
+ LOGP(DNM, LOGL_ERROR, "Trying to use ARFCN %d for hopping with no TRX configured for it", arfcn);
+ return 0;
+ }
+
+ /*
+ * [7:4] - TX address
+ * This must be the same number that was used when configuring the TX
+ * MO object with that target arfcn
+ *
+ * [3:0] - RX address
+ * The logical TRX number we're configuring the hopping sequence for
+ * This must basically match the MO object instance number
+ *
+ * ATM since we only support 1 MCTR, we use trx->nr
+ */
+ buf[0] = (trx->nr << 4) | ts->trx->nr;
+
+ /* ARFCN Number */
buf[1] = (arfcn >> 8);
buf[2] = (arfcn & 0xff);
+ /* C0 marker */
+ if (trx == trx->bts->c0)
+ buf[1] |= 0x04;
+
return 3;
}
@@ -1390,10 +1498,10 @@ static int om2k_gen_freq_list(uint8_t *list, struct gsm_bts_trx_ts *ts)
unsigned int i;
for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
if (bitvec_get_bit_pos(&ts->hopping.arfcns, i))
- cur += put_freq_list(cur, i);
+ cur += put_freq_list(cur, ts, i);
}
} else
- cur += put_freq_list(cur, ts->trx->arfcn);
+ cur += put_freq_list(cur, ts, ts->trx->arfcn);
len = cur - list;
@@ -1431,7 +1539,7 @@ int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
msgb_tv_put(msg, OM2K_DEI_EXT_RANGE, 0); /* Off */
/* Optional: Interference Rejection Combining */
msgb_tv_put(msg, OM2K_DEI_INTERF_REJ_COMB, 0x00);
- switch (ts->pchan_is) {
+ switch (ts->pchan_from_config) {
case GSM_PCHAN_CCCH:
msgb_tv_put(msg, OM2K_DEI_BA_PA_MFRMS, 0x06);
msgb_tv_put(msg, OM2K_DEI_BS_AG_BKS_RES, 0x01);
@@ -1475,7 +1583,7 @@ int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS,
sizeof(icm_bound_params), icm_bound_params);
msgb_tv_put(msg, OM2K_DEI_TTA, 10); /* Timer for Time Alignment */
- if (ts->pchan_is == GSM_PCHAN_TCH_H)
+ if (ts->pchan_from_config == GSM_PCHAN_TCH_H)
msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 1); /* TCH/H */
else
msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 0); /* TCH/F */
@@ -1670,6 +1778,9 @@ static void om2k_mo_st_wait_start_res(struct osmo_fsm_inst *fi, uint32_t event,
case OM2K_MO_CLS_CON:
abis_om2k_tx_con_conf_req(omfp->trx->bts);
break;
+ case OM2K_MO_CLS_MCTR:
+ abis_om2k_tx_mctr_conf_req(omfp->trx->bts);
+ break;
case OM2K_MO_CLS_TX:
abis_om2k_tx_tx_conf_req(omfp->trx);
break;
@@ -1937,6 +2048,7 @@ int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
case OM2K_MSGT_CON_CONF_REQ_ACK:
case OM2K_MSGT_IS_CONF_REQ_ACK:
+ case OM2K_MSGT_MCTR_CONF_REQ_ACK:
case OM2K_MSGT_RX_CONF_REQ_ACK:
case OM2K_MSGT_TF_CONF_REQ_ACK:
case OM2K_MSGT_TS_CONF_REQ_ACK:
@@ -1947,6 +2059,7 @@ int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
case OM2K_MSGT_CON_CONF_RES:
case OM2K_MSGT_IS_CONF_RES:
+ case OM2K_MSGT_MCTR_CONF_RES:
case OM2K_MSGT_RX_CONF_RES:
case OM2K_MSGT_TF_CONF_RES:
case OM2K_MSGT_TS_CONF_RES:
@@ -2012,7 +2125,7 @@ enum om2k_trx_state {
struct om2k_trx_fsm_priv {
struct gsm_bts_trx *trx;
- uint8_t next_ts_nr;
+ uint8_t cur_ts_nr;
};
static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2056,8 +2169,8 @@ static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *d
/* Initialize Timeslots after TX */
osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS,
TRX_FSM_TIMEOUT, 0);
- otfp->next_ts_nr = 0;
- ts = &otfp->trx->ts[otfp->next_ts_nr++];
+ otfp->cur_ts_nr = 0;
+ ts = &otfp->trx->ts[otfp->cur_ts_nr];
om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
&ts->rbs2000.om2k_mo);
}
@@ -2067,9 +2180,14 @@ static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *d
struct om2k_trx_fsm_priv *otfp = fi->priv;
struct gsm_bts_trx_ts *ts;
- if (otfp->next_ts_nr < 8) {
+ /* notify TS is ready */
+ ts = &otfp->trx->ts[otfp->cur_ts_nr];
+ osmo_fsm_inst_dispatch(ts->fi, TS_EV_OML_READY, NULL);
+
+ /* next ? */
+ if (++otfp->cur_ts_nr < 8) {
/* iterate to the next timeslot */
- ts = &otfp->trx->ts[otfp->next_ts_nr++];
+ ts = &otfp->trx->ts[otfp->cur_ts_nr];
om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
&ts->rbs2000.om2k_mo);
} else {
@@ -2179,6 +2297,8 @@ enum om2k_bts_event {
OM2K_BTS_EVT_IS_DONE,
OM2K_BTS_EVT_CON_DONE,
OM2K_BTS_EVT_TF_DONE,
+ OM2K_BTS_EVT_MCTR_DONE,
+ OM2K_BTS_EVT_TRX_LAPD_UP,
OM2K_BTS_EVT_TRX_DONE,
OM2K_BTS_EVT_STOP,
};
@@ -2189,6 +2309,8 @@ static const struct value_string om2k_bts_events[] = {
{ OM2K_BTS_EVT_IS_DONE, "IS-DONE" },
{ OM2K_BTS_EVT_CON_DONE, "CON-DONE" },
{ OM2K_BTS_EVT_TF_DONE, "TF-DONE" },
+ { OM2K_BTS_EVT_MCTR_DONE, "MCTR-DONE" },
+ { OM2K_BTS_EVT_TRX_LAPD_UP, "TRX-LAPD-UP" },
{ OM2K_BTS_EVT_TRX_DONE, "TRX-DONE" },
{ OM2K_BTS_EVT_STOP, "STOP" },
{ 0, NULL }
@@ -2200,6 +2322,8 @@ enum om2k_bts_state {
OM2K_BTS_S_WAIT_IS,
OM2K_BTS_S_WAIT_CON,
OM2K_BTS_S_WAIT_TF,
+ OM2K_BTS_S_WAIT_MCTR,
+ OM2K_BTS_S_WAIT_TRX_LAPD,
OM2K_BTS_S_WAIT_TRX,
OM2K_BTS_S_DONE,
OM2K_BTS_S_ERROR,
@@ -2263,10 +2387,37 @@ static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *
static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts_trx *trx;
+ struct gsm_bts *bts = obfp->bts;
OSMO_ASSERT(event == OM2K_BTS_EVT_IS_DONE);
+ /* If we're running OML >= G12R13, start MCTR, else skip directly to TRX */
+ if (bts->rbs2000.om2k_version[0].active >= 0x0c0d) {
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_MCTR,
+ BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(fi, OM2K_BTS_EVT_MCTR_DONE, bts->c0,
+ &bts->rbs2000.mctr.om2k_mo);
+ } else {
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD,
+ TRX_LAPD_TIMEOUT, 0);
+ }
+}
+
+static void om2k_bts_s_wait_mctr(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ OSMO_ASSERT(event == OM2K_BTS_EVT_MCTR_DONE);
+
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD,
+ TRX_LAPD_TIMEOUT, 0);
+}
+
+static void om2k_bts_s_wait_trx_lapd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct om2k_bts_fsm_priv *obfp = fi->priv;
+ struct gsm_bts_trx *trx;
+
+ OSMO_ASSERT(event == OM2K_BTS_EVT_TRX_LAPD_UP);
+
osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX,
BTS_FSM_TIMEOUT, 0);
obfp->next_trx_nr = 0;
@@ -2325,10 +2476,24 @@ static const struct osmo_fsm_state om2k_bts_states[] = {
[OM2K_BTS_S_WAIT_IS] = {
.in_event_mask = S(OM2K_BTS_EVT_IS_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_TRX),
+ S(OM2K_BTS_S_WAIT_MCTR) |
+ S(OM2K_BTS_S_WAIT_TRX_LAPD),
.name = "WAIT-IS",
.action = om2k_bts_s_wait_is,
},
+ [OM2K_BTS_S_WAIT_MCTR] = {
+ .in_event_mask = S(OM2K_BTS_EVT_MCTR_DONE),
+ .out_state_mask = S(OM2K_BTS_S_ERROR) |
+ S(OM2K_BTS_S_WAIT_TRX_LAPD),
+ .name = "WAIT-MCTR",
+ .action = om2k_bts_s_wait_mctr,
+ },
+ [OM2K_BTS_S_WAIT_TRX_LAPD] = {
+ .in_event_mask = S(OM2K_BTS_EVT_TRX_LAPD_UP),
+ .out_state_mask = S(OM2K_BTS_S_WAIT_TRX),
+ .name = "WAIT-TRX-LAPD",
+ .action = om2k_bts_s_wait_trx_lapd,
+ },
[OM2K_BTS_S_WAIT_TRX] = {
.in_event_mask = S(OM2K_BTS_EVT_TRX_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
@@ -2347,7 +2512,14 @@ static const struct osmo_fsm_state om2k_bts_states[] = {
static int om2k_bts_timer_cb(struct osmo_fsm_inst *fi)
{
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_ERROR, 0, 0);
+ switch (fi->state) {
+ case OM2K_BTS_S_WAIT_TRX_LAPD:
+ osmo_fsm_inst_dispatch(fi, OM2K_BTS_EVT_TRX_LAPD_UP, NULL);
+ break;
+ default:
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_ERROR, 0, 0);
+ break;
+ }
return 0;
}
@@ -2404,8 +2576,8 @@ static int abis_om2k_tx_negot_req_ack(struct gsm_bts *bts, const struct abis_om2
}
struct iwd_version {
- uint8_t gen_char[3+1];
- uint8_t rev_char[3+1];
+ char gen_char[3+1];
+ char rev_char[3+1];
};
struct iwd_type {
@@ -2416,11 +2588,13 @@ struct iwd_type {
static int om2k_rx_negot_req(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
struct iwd_type iwd_types[16];
uint8_t num_iwd_types = o2h->data[2];
uint8_t *cur = o2h->data+3;
- unsigned int i, v;
+ unsigned int i;
+ int v;
uint8_t out_buf[1024];
uint8_t *out_cur = out_buf+1;
@@ -2451,25 +2625,59 @@ static int om2k_rx_negot_req(struct msgb *msg)
/* Select the last version for each IWD type */
for (i = 0; i < ARRAY_SIZE(iwd_types); i++) {
struct iwd_type *type = &iwd_types[i];
- struct iwd_version *last_v;
+ struct iwd_version *sel_v = NULL, *alt_v = NULL;
+ uint16_t sel_ver, alt_ver = 0;
+ int gen, rev;
if (type->num_vers == 0)
continue;
out_num_types++;
- last_v = &type->v[type->num_vers-1];
+ for (v = type->num_vers-1; v >= 0; v--) {
+ if ((sscanf(type->v[v].gen_char, "G%2d", &gen) != 1) ||
+ (sscanf(type->v[v].rev_char, "R%2d", &rev) != 1))
+ continue;
+ sel_ver = (gen << 8) | rev;
+
+ if (!alt_v) {
+ alt_ver = sel_ver;
+ alt_v = &type->v[v];
+ }
+
+ if ((bts->rbs2000.om2k_version[i].limit != 0) &&
+ (bts->rbs2000.om2k_version[i].limit < sel_ver))
+ continue;
+
+ sel_v = &type->v[v];
+ break;
+ }
+ if (!sel_v) {
+ if (!alt_v) {
+ LOGP(DNM, LOGL_ERROR, "Couldn't find valid version for IWD Type %u."
+ "Skipping IWD ... this will most likely fail\n", i);
+ continue;
+ } else {
+ sel_v = alt_v;
+ sel_ver = alt_ver;
+ LOGP(DNM, LOGL_ERROR, "Couldn't find suitable version for IWD Type %u."
+ "Fallback to Gen %s Rev %s\n", i,
+ sel_v->gen_char, sel_v->rev_char);
+ }
+ }
+
+ bts->rbs2000.om2k_version[i].active = sel_ver;
*out_cur++ = i;
- memcpy(out_cur, last_v->gen_char, 3);
+ memcpy(out_cur, sel_v->gen_char, 3);
out_cur += 3;
- memcpy(out_cur, last_v->rev_char, 3);
+ memcpy(out_cur, sel_v->rev_char, 3);
out_cur += 3;
}
out_buf[0] = out_num_types;
- return abis_om2k_tx_negot_req_ack(sign_link->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
+ return abis_om2k_tx_negot_req_ack(bts, &o2h->mo, out_buf, out_cur - out_buf);
}
@@ -2713,6 +2921,9 @@ int abis_om2k_rcvmsg(struct msgb *msg)
case OM2K_MSGT_CON_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CON_CONF_RES_ACK);
break;
+ case OM2K_MSGT_MCTR_CONF_RES:
+ rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_MCTR_CONF_RES_ACK);
+ break;
case OM2K_MSGT_TX_CONF_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TX_CONF_RES_ACK);
break;
@@ -2740,8 +2951,8 @@ int abis_om2k_rcvmsg(struct msgb *msg)
case OM2K_MSGT_CAPA_RES:
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CAPA_RES_ACK);
break;
- case 0x0136: /* Unknown ... something for MCTR */
- rc = abis_om2k_tx_simple(bts, &o2h->mo, 0x0134);
+ case OM2K_MSGT_MCTR_STATS_REP:
+ rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_MCTR_STATS_REP_ACK);
break;
/* ERrors */
case OM2K_MSGT_START_REQ_REJ:
@@ -2751,6 +2962,7 @@ int abis_om2k_rcvmsg(struct msgb *msg)
case OM2K_MSGT_TEST_REQ_REJ:
case OM2K_MSGT_CON_CONF_REQ_REJ:
case OM2K_MSGT_IS_CONF_REQ_REJ:
+ case OM2K_MSGT_MCTR_CONF_REQ_REJ:
case OM2K_MSGT_TX_CONF_REQ_REJ:
case OM2K_MSGT_RX_CONF_REQ_REJ:
case OM2K_MSGT_TS_CONF_REQ_REJ:
@@ -2813,7 +3025,6 @@ void abis_om2k_trx_init(struct gsm_bts_trx *trx)
om2k_mo_init(&ts->rbs2000.om2k_mo, OM2K_MO_CLS_TS,
bts->nr, trx->nr, i);
OSMO_ASSERT(ts->fi);
- osmo_fsm_inst_dispatch(ts->fi, TS_EV_OML_READY, NULL);
}
}
@@ -2832,6 +3043,8 @@ void abis_om2k_bts_init(struct gsm_bts *bts)
bts->nr, 0xFF, 0);
om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF,
bts->nr, 0xFF, 0);
+ om2k_mo_init(&bts->rbs2000.mctr.om2k_mo, OM2K_MO_CLS_MCTR,
+ bts->nr, 0xFF, 0); // FIXME: There can be multiple MCTRs ...
}
static __attribute__((constructor)) void abis_om2k_init(void)
diff --git a/src/osmo-bsc/abis_om2000_vty.c b/src/osmo-bsc/abis_om2000_vty.c
index 972fff04a..222546f87 100644
--- a/src/osmo-bsc/abis_om2000_vty.c
+++ b/src/osmo-bsc/abis_om2000_vty.c
@@ -467,6 +467,40 @@ DEFUN(cfg_bts_alt_mode, cfg_bts_alt_mode_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_om2k_version_limit, cfg_bts_om2k_version_limit_cmd,
+ "om2000 version-limit (oml|rsl) gen <0-99> rev <0-99>",
+ "Configure OM2K specific parameters\n"
+ "Configure optional maximum protocol version to negotiate\n"
+ "Limit OML IWD version\n" "Limit RSL IWD version\n"
+ "Generation limit\n"
+ "Generation number to limit to (inclusive)\n"
+ "Revision limit\n"
+ "Revision number to limit to (inclusive)\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int iwd;
+
+ if (bts->type != GSM_BTS_TYPE_RBS2000) {
+ vty_out(vty, "%% Command only works for RBS2000%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[0], "oml"))
+ iwd = 0;
+ else if (!strcmp(argv[0], "rsl"))
+ iwd = 1;
+ else {
+ vty_out(vty, "%% Invalid IWD%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->rbs2000.om2k_version[iwd].limit = (atoi(argv[1]) << 8) | atoi(argv[2]);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_bts_is_conn_list, cfg_bts_is_conn_list_cmd,
"is-connection-list (add|del) <0-2047> <0-2047> <0-255>",
"Interface Switch Connection List\n"
@@ -591,6 +625,7 @@ void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
struct is_conn_group *igrp;
struct con_group *cgrp;
+ unsigned int i;
llist_for_each_entry(igrp, &bts->rbs2000.is.conn_groups, list)
vty_out(vty, " is-connection-list add %u %u %u%s",
@@ -604,6 +639,13 @@ void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
if (bts->rbs2000.use_superchannel)
vty_out(vty, " abis-lower-transport super-channel%s",
VTY_NEWLINE);
+ for (i = 0; i < 2; i++)
+ if (bts->rbs2000.om2k_version[i].limit)
+ vty_out(vty, " om2000 version-limit %s gen %02d rev %02d%s",
+ i ? "rsl" : "oml",
+ (bts->rbs2000.om2k_version[i].limit >> 8),
+ (bts->rbs2000.om2k_version[i].limit & 0xff),
+ VTY_NEWLINE);
}
int abis_om2k_vty_init(void)
@@ -631,6 +673,7 @@ int abis_om2k_vty_init(void)
install_element(BTS_NODE, &cfg_bts_is_conn_list_cmd);
install_element(BTS_NODE, &cfg_bts_alt_mode_cmd);
+ install_element(BTS_NODE, &cfg_bts_om2k_version_limit_cmd);
install_element(BTS_NODE, &cfg_om2k_con_group_cmd);
install_element(BTS_NODE, &del_om2k_con_group_cmd);
diff --git a/src/osmo-bsc/bsc_init.c b/src/osmo-bsc/bsc_init.c
index 0d5829622..d08e9c861 100644
--- a/src/osmo-bsc/bsc_init.c
+++ b/src/osmo-bsc/bsc_init.c
@@ -45,9 +45,7 @@
#include <stdbool.h>
static const struct osmo_stat_item_desc bsc_stat_desc[] = {
- { "msc_link", "MSC link status.", "", 16, 0 },
- { "num_bts_connected", "Number of currently connected BTS (OML links).", "", 16, 0 },
- { "num_trx_connected", "Number of currently connected TRX (RSL links).", "", 16, 0 },
+ { "num_bts:total", "Number of configured BTS for this BSC", "", 16, 0 },
};
static const struct osmo_stat_item_group_desc bsc_statg_desc = {
@@ -283,6 +281,11 @@ static struct gsm_network *bsc_network_init(void *ctx)
return NULL;
}
net->bsc_statg = osmo_stat_item_group_alloc(net, &bsc_statg_desc, 0);
+ if (!net->bsc_statg) {
+ rate_ctr_group_free(net->bsc_ctrs);
+ talloc_free(net);
+ return NULL;
+ }
INIT_LLIST_HEAD(&net->bts_rejected);
gsm_net_update_ctype(net);
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index f8bcee9a7..0fd462f33 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -2077,6 +2077,7 @@ DEFUN(cfg_bts,
/* allocate a new one */
bts = bsc_bts_alloc_register(gsmnet, GSM_BTS_TYPE_UNKNOWN,
HARDCODED_BSIC);
+ osmo_stat_item_inc(gsmnet->bsc_statg->items[BSC_STAT_NUM_BTS_TOTAL], 1);
/*
* Initialize bts->acc_ramp here. Else we could segfault while
* processing a configuration file with ACC ramping settings.
diff --git a/src/osmo-bsc/bts_ericsson_rbs2000.c b/src/osmo-bsc/bts_ericsson_rbs2000.c
index 4d1e91b0f..02ef46387 100644
--- a/src/osmo-bsc/bts_ericsson_rbs2000.c
+++ b/src/osmo-bsc/bts_ericsson_rbs2000.c
@@ -34,11 +34,15 @@
static void bootstrap_om_bts(struct gsm_bts *bts)
{
+ struct gsm_bts_trx *trx;
+
LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
- /* FIXME: this is global init, not bootstrapping */
+ /* Global init (not bootstrapping) */
abis_om2k_bts_init(bts);
- abis_om2k_trx_init(bts->c0);
+
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ abis_om2k_trx_init(trx);
/* TODO: Should we wait for a Failure report? */
om2k_bts_fsm_start(bts);
@@ -149,14 +153,16 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
case S_L_INP_LINE_NOALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI")
&& strcasecmp(isd->line->driver->name, "MISDN_LAPD")
- && strcasecmp(isd->line->driver->name, "UNIXSOCKET"))
+ && strcasecmp(isd->line->driver->name, "UNIXSOCKET")
+ && strcasecmp(isd->line->driver->name, "E1D"))
break;
start_sabm_in_line(isd->line, 1);
break;
case S_L_INP_LINE_ALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI")
&& strcasecmp(isd->line->driver->name, "MISDN_LAPD")
- && strcasecmp(isd->line->driver->name, "UNIXSOCKET"))
+ && strcasecmp(isd->line->driver->name, "UNIXSOCKET")
+ && strcasecmp(isd->line->driver->name, "E1D"))
break;
start_sabm_in_line(isd->line, 0);
break;
diff --git a/src/osmo-bsc/bts_ipaccess_nanobts.c b/src/osmo-bsc/bts_ipaccess_nanobts.c
index 8873ad4cb..f004c1598 100644
--- a/src/osmo-bsc/bts_ipaccess_nanobts.c
+++ b/src/osmo-bsc/bts_ipaccess_nanobts.c
@@ -397,8 +397,7 @@ void ipaccess_drop_rsl(struct gsm_bts_trx *trx, const char *reason)
LOG_TRX(trx, DLINP, LOGL_NOTICE, "Dropping RSL link: %s\n", reason);
e1inp_sign_link_destroy(trx->rsl_link);
trx->rsl_link = NULL;
- osmo_stat_item_set(trx->bts->bts_statg->items[BTS_STAT_NUM_RSL_CONNECTED], 0);
- osmo_stat_item_dec(trx->bts->network->bsc_statg->items[BSC_STAT_NUM_TRX_CONNECTED], 1);
+ osmo_stat_item_dec(trx->bts->bts_statg->items[BTS_STAT_RSL_CONNECTED], 1);
if (trx->bts->c0 == trx)
paging_flush_bts(trx->bts, NULL);
@@ -419,8 +418,7 @@ void ipaccess_drop_oml(struct gsm_bts *bts, const char *reason)
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
bts->uptime = 0;
- osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_NUM_OML_CONNECTED], 0);
- osmo_stat_item_dec(bts->network->bsc_statg->items[BSC_STAT_NUM_BTS_CONNECTED], 1);
+ osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_OML_CONNECTED], 1);
/* we have issues reconnecting RSL, drop everything. */
llist_for_each_entry(trx, &bts->trx_list, list)
@@ -562,8 +560,7 @@ ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line,
sign_link->tei, sign_link->sapi);
sign_link->trx->bts->ip_access.flags |= OML_UP;
}
- osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_NUM_OML_CONNECTED], 1);
- osmo_stat_item_inc(bts->network->bsc_statg->items[BSC_STAT_NUM_BTS_CONNECTED], 1);
+ osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_OML_CONNECTED], 1);
break;
case E1INP_SIGN_RSL: {
struct e1inp_ts *ts;
@@ -591,9 +588,8 @@ ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line,
sign_link->trx->bts->ip_access.flags |=
(RSL_UP << sign_link->trx->nr);
}
+ osmo_stat_item_inc(bts->bts_statg->items[BTS_STAT_RSL_CONNECTED], 1);
break;
- osmo_stat_item_set(bts->bts_statg->items[BTS_STAT_NUM_RSL_CONNECTED], 1);
- osmo_stat_item_inc(bts->network->bsc_statg->items[BSC_STAT_NUM_TRX_CONNECTED], 1);
}
default:
break;
diff --git a/src/osmo-bsc/bts_nokia_site.c b/src/osmo-bsc/bts_nokia_site.c
index 66972c2b5..cde0afa97 100644
--- a/src/osmo-bsc/bts_nokia_site.c
+++ b/src/osmo-bsc/bts_nokia_site.c
@@ -41,6 +41,12 @@
#include <osmocom/abis/lapd.h>
+enum reset_timer_state {
+ RESET_T_NONE = 0,
+ RESET_T_STOP_LAPD = 1, /* first timer expiration: stop LAPD SAP */
+ RESET_T_RESTART_LAPD = 2, /* second timer expiration: restart LAPD SAP */
+};
+
/* TODO: put in a separate file ? */
extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg);
@@ -1461,18 +1467,28 @@ static void reset_timer_cb(void *_bts)
struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
struct e1inp_line *line;
- bts->nokia.wait_reset = 0;
-
/* OML link */
line = e1inp_line_find(e1_link->e1_nr);
if (!line) {
- LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
- "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
+ LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to non-existing E1 line %u\n",
+ bts->nr, e1_link->e1_nr);
return;
}
- start_sabm_in_line(line, 0, -1); /* stop all first */
- start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
+ switch (bts->nokia.wait_reset) {
+ case RESET_T_NONE: /* shouldn't happen */
+ break;
+ case RESET_T_STOP_LAPD:
+ start_sabm_in_line(line, 0, -1); /* stop all first */
+ bts->nokia.wait_reset = RESET_T_RESTART_LAPD;
+ osmo_timer_schedule(&bts->nokia.reset_timer, bts->nokia.bts_reset_timer_cnf, 0);
+ break;
+ case RESET_T_RESTART_LAPD:
+ bts->nokia.wait_reset = 0;
+ start_sabm_in_line(line, 0, -1); /* stop all first */
+ start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
+ break;
+ }
}
/* TODO: put in a separate file ? */
@@ -1574,25 +1590,16 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
(function handle_ts1_read()) and ignoring the received data.
It seems to be necessary for the MetroSite too.
*/
- bts->nokia.wait_reset = 1;
-
- osmo_timer_setup(&bts->nokia.reset_timer,
- reset_timer_cb, bts);
- osmo_timer_schedule(&bts->nokia.reset_timer, bts->nokia.bts_reset_timer_cnf, 0);
-
- struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
- struct e1inp_line *line;
- /* OML link */
- line = e1inp_line_find(e1_link->e1_nr);
- if (!line) {
- LOGP(DLINP, LOGL_ERROR,
- "BTS %u OML link referring to "
- "non-existing E1 line %u\n", bts->nr,
- e1_link->e1_nr);
- return -ENOMEM;
- }
- start_sabm_in_line(line, 0, -1); /* stop all first */
+ /* we cannot delete / stop the OML LAPD SAP right here, as we are in
+ * the middle of processing an LAPD I frame and are subsequently returning
+ * back to the LAPD I frame processing code that assumes the SAP is still
+ * active. So we first schedule the timer at 0ms in the future, where we
+ * kill all LAPD SAP and re-arm the timer for the reset duration, after which
+ * we re-create them */
+ bts->nokia.wait_reset = RESET_T_STOP_LAPD;
+ osmo_timer_setup(&bts->nokia.reset_timer, reset_timer_cb, bts);
+ osmo_timer_schedule(&bts->nokia.reset_timer, 0, 0);
}
/* ACK for CONF DATA message ? */
diff --git a/src/osmo-bsc/chan_alloc.c b/src/osmo-bsc/chan_alloc.c
index bea16201c..75cea7162 100644
--- a/src/osmo-bsc/chan_alloc.c
+++ b/src/osmo-bsc/chan_alloc.c
@@ -37,6 +37,7 @@
#include <osmocom/core/talloc.h>
+/* Update channel load calculation for the given BTS */
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
@@ -58,20 +59,28 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
if (!nm_is_running(&ts->mo.nm_state))
continue;
- /* dynamic timeslots have to be counted separately
+ /* Dynamic timeslots have to be counted separately
* when not in TCH/F or TCH/H mode because they don't
- * have an lchan's allocated to them */
- if ( ( ts->pchan_on_init == GSM_PCHAN_TCH_F_TCH_H_PDCH
- || ts->pchan_on_init == GSM_PCHAN_TCH_F_PDCH)
- && ( ts->pchan_is == GSM_PCHAN_NONE
- || ts->pchan_is == GSM_PCHAN_PDCH)) {
+ * have an lchan's allocated to them. At the same time,
+ * dynamic timeslots in NONE and PDCH modes are same
+ * as in UNUSED mode from the CS channel load perspective
+ * beause they can be switched to TCH mode at any moment.
+ * I.e. they are "available" for TCH. */
+ if ((ts->pchan_on_init == GSM_PCHAN_TCH_F_TCH_H_PDCH ||
+ ts->pchan_on_init == GSM_PCHAN_TCH_F_PDCH) &&
+ (ts->pchan_is == GSM_PCHAN_NONE ||
+ ts->pchan_is == GSM_PCHAN_PDCH)) {
pl->total++;
}
- /* count allocated logical channels.
- * Note: When GSM_PCHAN_TCH_F_TCH_H_PDCH is allocation
- * in TCH/H mode, this leads to changing the total
- * count vs the TCH/F allocation */
+ /* Count allocated logical channels.
+ * Note: A GSM_PCHAN_TCH_F_TCH_H_PDCH can be switched
+ * to a single TCH/F or to two TCH/H. So when it's in
+ * the TCH/H mode, total number of available channels
+ * is 1 more than when it's in the TCH/F mode.
+ * I.e. "total" count will fluctuate depending on
+ * whether GSM_PCHAN_TCH_F_TCH_H_PDCH timeslot is
+ * in TCH/F or TCH/H (or in NONE/PDCH) mode. */
ts_for_each_lchan(lchan, ts) {
/* don't even count CBCH slots in total */
if (lchan->type == GSM_LCHAN_CBCH)
@@ -91,6 +100,7 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
}
}
+/* Update channel load calculation for all BTS in the BSC */
void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
{
struct gsm_bts *bts;
diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c
index 497e1b836..8b50805e3 100644
--- a/src/osmo-bsc/gsm_data.c
+++ b/src/osmo-bsc/gsm_data.c
@@ -370,28 +370,28 @@ void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value)
}
static const struct osmo_stat_item_desc bts_stat_desc[] = {
- { "chanloadavg", "Channel load average.", "%", 16, 0 },
- { "chan_ccch_sdcch4_used", "Number of CCCH+SDCCH4 channels used.", "", 16, 0 },
- { "chan_ccch_sdcch4_total", "Number of CCCH+SDCCH4 channels total.", "", 16, 0 },
- { "chan_tch_f_used", "Number of TCH/F channels used.", "", 16, 0 },
- { "chan_tch_f_total", "Number of TCH/F channels total.", "", 16, 0 },
- { "chan_tch_h_used", "Number of TCH/H channels used.", "", 16, 0 },
- { "chan_tch_h_total", "Number of TCH/H channels total.", "", 16, 0 },
- { "chan_sdcch8_used", "Number of SDCCH8 channels used.", "", 16, 0 },
- { "chan_sdcch8_total", "Number of SDCCH8 channels total.", "", 16, 0 },
- { "chan_tch_f_pdch_used", "Number of TCH/F_PDCH channels used.", "", 16, 0 },
- { "chan_tch_f_pdch_total", "Number of TCH/F_PDCH channels total.", "", 16, 0 },
- { "chan_ccch_sdcch4_cbch_used", "Number of CCCH+SDCCH4+CBCH channels used.", "", 16, 0 },
- { "chan_ccch_sdcch4_cbch_total", "Number of CCCH+SDCCH4+CBCH channels total.", "", 16, 0 },
- { "chan_sdcch8_cbch_used", "Number of SDCCH8+CBCH channels used.", "", 16, 0 },
- { "chan_sdcch8_cbch_total", "Number of SDCCH8+CBCH channels total.", "", 16, 0 },
- { "chan_tch_f_tch_h_pdch_used", "Number of TCH/F_TCH/H_PDCH channels used.", "", 16, 0 },
- { "chan_tch_f_tch_h_pdch_total", "Number of TCH/F_TCH/H_PDCH channels total.", "", 16, 0 },
- { "T3122", "T3122 IMMEDIATE ASSIGNMENT REJECT wait indicator.", "s", 16, GSM_T3122_DEFAULT },
+ { "chanloadavg", "Channel load average", "%", 16, 0 },
+ { "chan_ccch_sdcch4:used", "Number of CCCH+SDCCH4 channels used", "", 16, 0 },
+ { "chan_ccch_sdcch4:total", "Number of CCCH+SDCCH4 channels total", "", 16, 0 },
+ { "chan_tch_f:used", "Number of TCH/F channels used", "", 16, 0 },
+ { "chan_tch_f:total", "Number of TCH/F channels total", "", 16, 0 },
+ { "chan_tch_h:used", "Number of TCH/H channels used", "", 16, 0 },
+ { "chan_tch_h:total", "Number of TCH/H channels total", "", 16, 0 },
+ { "chan_sdcch8:used", "Number of SDCCH8 channels used", "", 16, 0 },
+ { "chan_sdcch8:total", "Number of SDCCH8 channels total", "", 16, 0 },
+ { "chan_tch_f_pdch:used", "Number of TCH/F_PDCH channels used", "", 16, 0 },
+ { "chan_tch_f_pdch:total", "Number of TCH/F_PDCH channels total", "", 16, 0 },
+ { "chan_ccch_sdcch4_cbch:used", "Number of CCCH+SDCCH4+CBCH channels used", "", 16, 0 },
+ { "chan_ccch_sdcch4_cbch:total", "Number of CCCH+SDCCH4+CBCH channels total", "", 16, 0 },
+ { "chan_sdcch8_cbch:used", "Number of SDCCH8+CBCH channels used", "", 16, 0 },
+ { "chan_sdcch8_cbch:total", "Number of SDCCH8+CBCH channels total", "", 16, 0 },
+ { "chan_tch_f_tch_h_pdch:used", "Number of TCH/F_TCH/H_PDCH channels used", "", 16, 0 },
+ { "chan_tch_f_tch_h_pdch:total", "Number of TCH/F_TCH/H_PDCH channels total", "", 16, 0 },
+ { "T3122", "T3122 IMMEDIATE ASSIGNMENT REJECT wait indicator", "s", 16, GSM_T3122_DEFAULT },
{ "rach_busy", "RACH slots with signal above threshold", "%", 16, 0 },
{ "rach_access", "RACH slots with access bursts in them", "%", 16, 0 },
- { "num_oml_connected", "Number of OML links connected", "", 16, 0 },
- { "num_rsl_connected", "Number of RSL links connected", "", 16, 0 },
+ { "oml_connected", "Number of OML links connected", "", 16, 0 },
+ { "rsl_connected", "Number of RSL links connected", "", 16, 0 },
};
static const struct osmo_stat_item_group_desc bts_statg_desc = {
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 1ba490faa..f1e43be5a 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -1007,6 +1007,7 @@ static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
struct msgb *msg, unsigned int length)
{
int ret = 0;
+ struct rate_ctr *ctrs = msc->msc_ctrs->ctr;
if (length < 1) {
LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
@@ -1018,15 +1019,19 @@ static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
switch (msg->l4h[0]) {
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_UDT_RESET_ACKNOWLEDGE]);
ret = bssmap_handle_reset_ack(msc, msg, length);
break;
case BSS_MAP_MSG_RESET:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_UDT_RESET]);
ret = bssmap_handle_reset(msc, msg, length);
break;
case BSS_MAP_MSG_PAGING:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_UDT_PAGING]);
ret = bssmap_handle_paging(msc, msg, length);
break;
default:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_UDT_UNKNOWN]);
LOGP(DMSC, LOGL_NOTICE, "Received unimplemented BSSMAP UDT %s\n",
gsm0808_bssmap_name(msg->l4h[0]));
break;
@@ -1039,6 +1044,7 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length)
{
int ret = 0;
+ struct rate_ctr *ctrs = conn->sccp.msc->msc_ctrs->ctr;
if (length < 1) {
LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
@@ -1050,24 +1056,31 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn,
switch (msg->l4h[0]) {
case BSS_MAP_MSG_CLEAR_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_CLEAR_CMD]);
ret = bssmap_handle_clear_cmd(conn, msg, length);
break;
case BSS_MAP_MSG_CIPHER_MODE_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_CIPHER_MODE_CMD]);
ret = bssmap_handle_cipher_mode(conn, msg, length);
break;
case BSS_MAP_MSG_ASSIGMENT_RQST:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_ASSIGMENT_RQST]);
ret = bssmap_handle_assignm_req(conn, msg, length);
break;
case BSS_MAP_MSG_LCLS_CONNECT_CTRL:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_LCLS_CONNECT_CTRL]);
ret = bssmap_handle_lcls_connect_ctrl(conn, msg, length);
break;
case BSS_MAP_MSG_HANDOVER_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_HANDOVER_CMD]);
ret = bssmap_handle_handover_cmd(conn, msg, length);
break;
case BSS_MAP_MSG_CLASSMARK_RQST:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_CLASSMARK_RQST]);
ret = gsm48_send_rr_classmark_enquiry(conn->lchan);
break;
default:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UNKNOWN]);
LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
gsm0808_bssmap_name(msg->l4h[0]));
break;
@@ -1091,6 +1104,7 @@ static int dtap_rcvmsg(struct gsm_subscriber_connection *conn,
struct msgb *gsm48;
uint8_t *data;
int rc, dtap_rc;
+ struct rate_ctr *ctrs = conn->sccp.msc->msc_ctrs->ctr;
LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n",
osmo_hexdump(msg->l3h, length));
@@ -1102,17 +1116,20 @@ static int dtap_rcvmsg(struct gsm_subscriber_connection *conn,
header = (struct dtap_header *) msg->l3h;
if (sizeof(*header) >= length) {
- LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %zu got: %u\n", sizeof(*header), length);
- LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
- return -1;
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DTAP_ERROR]);
+ LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %zu got: %u, hex: %s\n",
+ sizeof(*header), length, osmo_hexdump(msg->l3h, length));
+ return -1;
}
if (header->length > length - sizeof(*header)) {
- LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
- LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DTAP_ERROR]);
+ LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit. Wanted: %u got: %zu, hex: %s\n",
+ header->length, length - sizeof(*header), osmo_hexdump(msg->l3h, length));
return -1;
}
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DTAP_MSG]);
LOGP(DMSC, LOGL_INFO, "Rx MSC DTAP, SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
/* forward the data */
diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c
index 24c8c6d99..d4d7bec1f 100644
--- a/src/osmo-bsc/osmo_bsc_msc.c
+++ b/src/osmo-bsc/osmo_bsc_msc.c
@@ -43,6 +43,43 @@
#include <netinet/tcp.h>
#include <unistd.h>
+static const struct rate_ctr_desc msc_ctr_description[] = {
+ [MSC_CTR_BSSMAP_RX_UDT_RESET_ACKNOWLEDGE] = {"bssmap:rx_udt_reset_acknowledge", "Number of received BSSMAP UDT RESET ACKNOWLEDGE messages"},
+ [MSC_CTR_BSSMAP_RX_UDT_RESET] = {"bssmap:rx_udt_reset", "Number of received BSSMAP UDT RESET messages"},
+ [MSC_CTR_BSSMAP_RX_UDT_PAGING] = {"bssmap:rx_udt_paging", "Number of received BSSMAP UDT PAGING messages"},
+ [MSC_CTR_BSSMAP_RX_UDT_UNKNOWN] = {"bssmap:rx_udt_unknown", "Number of received BSSMAP unknown UDT messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_CLEAR_CMD] = {"bssmap:rx_dt1_clear_cmd", "Number of received BSSMAP DT1 CLEAR CMD messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_CIPHER_MODE_CMD] = {"bssmap:rx_dt1_cipher_mode_cmd", "Number of received BSSMAP DT1 CIPHER MODE CMD messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_ASSIGMENT_RQST] = {"bssmap:rx_dt1_assignment_rqst", "Number of received BSSMAP DT1 ASSIGMENT RQST messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_LCLS_CONNECT_CTRL] = {"bssmap:rx_dt1_lcls_connect_ctrl", "Number of received BSSMAP DT1 LCLS CONNECT CTRL messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_HANDOVER_CMD] = {"bssmap:rx_dt1_handover_cmd", "Number of received BSSMAP DT1 HANDOVER CMD messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_CLASSMARK_RQST] = {"bssmap:rx_dt1_classmark_rqst", "Number of received BSSMAP DT1 CLASSMARK RQST messages"},
+ [MSC_CTR_BSSMAP_RX_DT1_UNKNOWN] = {"bssmap:rx_dt1_unknown", "Number of received BSSMAP unknown DT1 messages"},
+ [MSC_CTR_BSSMAP_RX_DTAP_MSG] = {"bssmap:rx_dtap_msg", "Number of received BSSMAP DTAP messages"},
+ [MSC_CTR_BSSMAP_RX_DTAP_ERROR] = {"bssmap:rx_dtap_error", "Number of received BSSMAP DATP messages with errors"},
+};
+
+static const struct rate_ctr_group_desc msc_ctrg_desc = {
+ "msc",
+ "mobile switching center",
+ OSMO_STATS_CLASS_GLOBAL,
+ ARRAY_SIZE(msc_ctr_description),
+ msc_ctr_description,
+};
+
+static const struct osmo_stat_item_desc msc_stat_desc[] = {
+ { "msc_links:active", "Number of active MSC links", "", 16, 0 },
+ { "msc_links:total", "Number of configured MSC links", "", 16, 0 },
+};
+
+static const struct osmo_stat_item_group_desc msc_statg_desc = {
+ .group_name_prefix = "msc",
+ .group_description = "mobile switching center",
+ .class_id = OSMO_STATS_CLASS_GLOBAL,
+ .num_items = ARRAY_SIZE(msc_stat_desc),
+ .item_desc = msc_stat_desc,
+};
+
int osmo_bsc_msc_init(struct bsc_msc_data *msc)
{
struct gsm_network *net = msc->network;
@@ -91,6 +128,19 @@ struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
if (!msc_data)
return NULL;
+ /* init statistics */
+ msc_data->msc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, nr);
+ if (!msc_data->msc_ctrs) {
+ talloc_free(msc_data);
+ return NULL;
+ }
+ msc_data->msc_statg = osmo_stat_item_group_alloc(net, &msc_statg_desc, nr);
+ if (!msc_data->msc_statg) {
+ rate_ctr_group_free(msc_data->msc_ctrs);
+ talloc_free(msc_data);
+ return NULL;
+ }
+
llist_add_tail(&msc_data->entry, &net->bsc_data->mscs);
/* Init back pointer */
diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c
index 50b03ce47..e4530bfd1 100644
--- a/src/osmo-bsc/osmo_bsc_sigtran.c
+++ b/src/osmo-bsc/osmo_bsc_sigtran.c
@@ -143,14 +143,14 @@ static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_add
return NULL;
}
-/* Send data to MSC, use the connection id which MSC it is */
+/* Received data from MSC, use the connection id which MSC it is */
static int handle_data_from_msc(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
msg->l3h = msgb_l2(msg);
return bsc_handle_dt(conn, msg, msgb_l2len(msg));
}
-/* Sent unitdata to MSC, use the point code to determine which MSC it is */
+/* Received unitdata from MSC, use the point code to determine which MSC it is */
static int handle_unitdata_from_msc(const struct osmo_sccp_addr *msc_addr, struct msgb *msg,
const struct osmo_sccp_user *scu)
{
@@ -215,7 +215,7 @@ refuse:
return rc;
}
-/* Callback function, called by the SSCP stack when data arrives */
+/* Callback function, called by the SCCP stack when data arrives */
static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;