diff options
-rw-r--r-- | TODO-RELEASE | 3 | ||||
-rw-r--r-- | include/osmocom/bsc/bsc_msc_data.h | 1 | ||||
-rw-r--r-- | include/osmocom/bsc/gsm_data.h | 52 | ||||
-rw-r--r-- | src/osmo-bsc/abis_rsl.c | 4 | ||||
-rw-r--r-- | src/osmo-bsc/bsc_vty.c | 5 | ||||
-rw-r--r-- | src/osmo-bsc/chan_alloc.c | 8 | ||||
-rw-r--r-- | src/osmo-bsc/gsm_08_08.c | 2 | ||||
-rw-r--r-- | src/osmo-bsc/gsm_data.c | 2 | ||||
-rw-r--r-- | src/osmo-bsc/lchan_fsm.c | 32 | ||||
-rw-r--r-- | src/osmo-bsc/osmo_bsc_bssap.c | 64 | ||||
-rw-r--r-- | src/osmo-bsc/osmo_bsc_filter.c | 3 | ||||
-rw-r--r-- | src/osmo-bsc/osmo_bsc_msc.c | 1 | ||||
-rw-r--r-- | src/osmo-bsc/timeslot_fsm.c | 77 | ||||
-rw-r--r-- | tests/bsc/bsc_test.c | 11 |
14 files changed, 245 insertions, 20 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE index dde4b72f2..e2fa427b3 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -8,3 +8,6 @@ # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line manual needs common chapter cs7-config.adoc from osmo-gsm-manuals > 0.3.0 +libosmocore struct gsm0808_diagnostics Depends on libosmocore > 1.3.0 +libosmocore gsm0808_diagnostics_octet_location_str() Depends on libosmocore > 1.3.0 +libosmocore gsm0808_diagnostics_bit_location_str() Depends on libosmocore > 1.3.0 diff --git a/include/osmocom/bsc/bsc_msc_data.h b/include/osmocom/bsc/bsc_msc_data.h index 74a6f3ce2..fc816b4fd 100644 --- a/include/osmocom/bsc/bsc_msc_data.h +++ b/include/osmocom/bsc/bsc_msc_data.h @@ -69,6 +69,7 @@ enum { 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_CONFUSION, MSC_CTR_BSSMAP_RX_DT1_UNKNOWN, MSC_CTR_BSSMAP_RX_DT1_DTAP, MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR, diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 17da79d43..41c65fc9b 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -1396,7 +1396,7 @@ static inline struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *con void conn_update_ms_power_class(struct gsm_subscriber_connection *conn, uint8_t power_class); void lchan_update_ms_power_ctrl_level(struct gsm_lchan *lchan, int ms_power_dbm); -enum { +enum bts_counter_id { BTS_CTR_CHREQ_TOTAL, BTS_CTR_CHREQ_NO_CHANNEL, BTS_CTR_CHAN_RF_FAIL, @@ -1412,11 +1412,33 @@ enum { BTS_CTR_PAGING_ALREADY, BTS_CTR_PAGING_RESPONDED, BTS_CTR_PAGING_EXPIRED, + BTS_CTR_PAGING_NON_ACTIVE, BTS_CTR_CHAN_ACT_TOTAL, BTS_CTR_CHAN_ACT_NACK, BTS_CTR_RSL_UNKNOWN, BTS_CTR_RSL_IPA_NACK, BTS_CTR_MODE_MODIFY_NACK, + BTS_CTR_LCHAN_BORKEN_FROM_UNUSED, + BTS_CTR_LCHAN_BORKEN_FROM_WAIT_ACTIV_ACK, + BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RF_RELEASE_ACK, + BTS_CTR_LCHAN_BORKEN_FROM_BORKEN, + BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN, + BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK, + BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK, + BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK, + BTS_CTR_LCHAN_BORKEN_EV_VTY, + BTS_CTR_LCHAN_BORKEN_EV_CLEANUP, + BTS_CTR_TS_BORKEN_FROM_NOT_INITIALIZED, + BTS_CTR_TS_BORKEN_FROM_UNUSED, + BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_ACT, + BTS_CTR_TS_BORKEN_FROM_PDCH, + BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_DEACT, + BTS_CTR_TS_BORKEN_FROM_IN_USE, + BTS_CTR_TS_BORKEN_FROM_BORKEN, + BTS_CTR_TS_BORKEN_FROM_UNKNOWN, + BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK, + BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK, + BTS_CTR_TS_BORKEN_EV_CLEANUP, }; static const struct rate_ctr_desc bts_ctr_description[] = { @@ -1436,11 +1458,35 @@ static const struct rate_ctr_desc bts_ctr_description[] = { [BTS_CTR_PAGING_ALREADY] = {"paging:already", "Paging attempts ignored as subscriber was already being paged."}, [BTS_CTR_PAGING_RESPONDED] = {"paging:responded", "Paging attempts with successful paging response."}, [BTS_CTR_PAGING_EXPIRED] = {"paging:expired", "Paging Request expired because of timeout T3113."}, + [BTS_CTR_PAGING_NON_ACTIVE] = {"paging:non_active", "Non active subscriber responded to paging."}, [BTS_CTR_CHAN_ACT_TOTAL] = {"chan_act:total", "Total number of Channel Activations."}, [BTS_CTR_CHAN_ACT_NACK] = {"chan_act:nack", "Number of Channel Activations that the BTS NACKed"}, [BTS_CTR_RSL_UNKNOWN] = {"rsl:unknown", "Number of unknown/unsupported RSL messages received from BTS"}, [BTS_CTR_RSL_IPA_NACK] = {"rsl:ipa_nack", "Number of IPA (RTP/dyn-PDCH) related NACKs received from BTS"}, [BTS_CTR_MODE_MODIFY_NACK] = {"chan:mode_modify_nack", "Number of Channel Mode Modify NACKs received from BTS"}, + + /* lchan/TS BORKEN state counters */ + [BTS_CTR_LCHAN_BORKEN_FROM_UNUSED] = {"lchan_borken:from_state:unused", "Transitions from lchan UNUSED state to BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_FROM_WAIT_ACTIV_ACK] = {"lchan_borken:from_state:wait_activ_ack", "Transitions from lchan WAIT_ACTIV_ACK state to BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RF_RELEASE_ACK] = {"lchan_borken:from_state:wait_rf_release_ack", "Transitions from lchan WAIT_RF_RELEASE_ACK state to BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_FROM_BORKEN] = {"lchan_borken:from_state:borken", "Transitions from lchan BORKEN state to BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN] = {"lchan_borken:from_state:unknown", "Transitions from an unknown lchan state to BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK] = {"lchan_borken:event:chan_activ_ack", "CHAN_ACTIV_ACK received in the lchan BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK] = {"lchan_borken:event:chan_activ_nack", "CHAN_ACTIV_NACK received in the lchan BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK] = {"lchan_borken:event:rf_chan_rel_ack", "RF_CHAN_REL_ACK received in the lchan BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_EV_VTY] = {"lchan_borken:event:vty", "VTY commands received in the lchan BORKEN state"}, + [BTS_CTR_LCHAN_BORKEN_EV_CLEANUP] = {"lchan_borken:event:cleanup", "lchan in a BORKEN state is cleaned up (BTS shuts down?)"}, + [BTS_CTR_TS_BORKEN_FROM_NOT_INITIALIZED] = {"ts_borken:from_state:not_initialized", "Transitions from TS NOT_INITIALIZED state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_UNUSED] = {"ts_borken:from_state:unused", "Transitions from TS UNUSED state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_ACT] = {"ts_borken:from_state:wait_pdch_act", "Transitions from TS WAIT_PDCH_ACT state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_PDCH] = {"ts_borken:from_state:pdch", "Transitions from TS PDCH state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_DEACT] = {"ts_borken:from_state:wait_pdch_deact", "Transitions from TS WAIT_PDCH_DEACT state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_IN_USE] = {"ts_borken:from_state:in_use", "Transitions from TS IN_USE state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_BORKEN] = {"ts_borken:from_state:borken", "Transitions from TS BORKEN state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_FROM_UNKNOWN] = {"ts_borken:from_state:unknown", "Transitions from an unknown TS state to BORKEN state"}, + [BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK] = {"ts_borken:event:pdch_act_ack_nack", "PDCH_ACT_ACK/NACK received in the TS BORKEN state"}, + [BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK] = {"ts_borken:event:pdch_deact_ack_nack", "PDCH_DEACT_ACK/NACK received in the TS BORKEN state"}, + [BTS_CTR_TS_BORKEN_EV_CLEANUP] = {"ts_borken:event:cleanup", "TS in a BORKEN state is cleaned up (BTS shuts down?)"}, }; static const struct rate_ctr_group_desc bts_ctrg_desc = { @@ -1474,6 +1520,8 @@ enum { BTS_STAT_RACH_ACCESS, BTS_STAT_OML_CONNECTED, BTS_STAT_RSL_CONNECTED, + BTS_STAT_LCHAN_BORKEN, + BTS_STAT_TS_BORKEN, }; enum { @@ -1506,6 +1554,7 @@ enum { BSC_CTR_PAGING_ATTEMPTED, BSC_CTR_PAGING_DETACHED, BSC_CTR_PAGING_RESPONDED, + BSC_CTR_PAGING_NON_ACTIVE, BSC_CTR_UNKNOWN_UNIT_ID, }; @@ -1550,6 +1599,7 @@ static const struct rate_ctr_desc bsc_ctr_description[] = { [BSC_CTR_PAGING_ATTEMPTED] = {"paging:attempted", "Paging attempts for a subscriber."}, [BSC_CTR_PAGING_DETACHED] = {"paging:detached", "Paging request send failures because no responsible BTS was found."}, [BSC_CTR_PAGING_RESPONDED] = {"paging:responded", "Paging attempts with successful response."}, + [BSC_CTR_PAGING_NON_ACTIVE] = {"paging:non_active", "Paging response for non active subscriber."}, [BSC_CTR_UNKNOWN_UNIT_ID] = {"abis:unknown_unit_id", "Connection attempts from unknown IPA CCM Unit ID."}, }; diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index a5e5f5140..4a1d31476 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -1369,7 +1369,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* Determine channel request cause code */ chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n", + LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n", get_value_string(gsm_chreq_descs, chreq_reason), rqd_ref->ra, bts->network->neci, chreq_reason); /* Handle PDCH related rach requests (in case of BSC-co-located-PCU */ @@ -1687,7 +1687,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) } break; case RSL_MT_EST_CONF: - LOG_LCHAN(msg->lchan, LOGL_ERROR, "SAPI=%u ESTABLISH CONFIRM\n", sapi); + LOG_LCHAN(msg->lchan, LOGL_DEBUG, "SAPI=%u ESTABLISH CONFIRM\n", sapi); msg->lchan->sapis[sapi] = LCHAN_SAPI_NET; rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_EST_CONF); diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c index 30f685faa..d699cf7ba 100644 --- a/src/osmo-bsc/bsc_vty.c +++ b/src/osmo-bsc/bsc_vty.c @@ -5018,9 +5018,10 @@ DEFUN_HIDDEN(lchan_set_borken, lchan_set_borken_cmd, return CMD_WARNING; } } else { - if (lchan->fi->state == LCHAN_ST_BORKEN) + if (lchan->fi->state == LCHAN_ST_BORKEN) { + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_VTY]); osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_UNUSED, 0, 0); - else { + } else { vty_out(vty, "%% lchan is in state %s, only lchans that are in state %s may be moved to state %s manually%s", osmo_fsm_state_name(lchan->fi->fsm, lchan->fi->state), diff --git a/src/osmo-bsc/chan_alloc.c b/src/osmo-bsc/chan_alloc.c index 27c49cd0e..eeb6b0a1b 100644 --- a/src/osmo-bsc/chan_alloc.c +++ b/src/osmo-bsc/chan_alloc.c @@ -87,6 +87,14 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) pl->total++; + /* lchans under a BORKEN/NOT_INITIALIZED TS should + * be counted as used just as BORKEN lchans under + * a normal TS */ + if (!ts_is_usable(ts)) { + pl->used++; + continue; + } + switch (lchan->fi->state) { case LCHAN_ST_UNUSED: break; diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c index 4f9c69eb6..d48c9f72c 100644 --- a/src/osmo-bsc/gsm_08_08.c +++ b/src/osmo-bsc/gsm_08_08.c @@ -388,6 +388,8 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb if (!subscr) { LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n"); + rate_ctr_inc(&conn->lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_PAGING_NON_ACTIVE]); + rate_ctr_inc(&conn->network->bsc_ctrs->ctr[BSC_CTR_PAGING_NON_ACTIVE]); return -1; } diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c index 2847f388f..c34f06cb1 100644 --- a/src/osmo-bsc/gsm_data.c +++ b/src/osmo-bsc/gsm_data.c @@ -392,6 +392,8 @@ static const struct osmo_stat_item_desc bts_stat_desc[] = { { "rach_access", "RACH slots with access bursts in them", "%", 16, 0 }, { "oml_connected", "Number of OML links connected", "", 16, 0 }, { "rsl_connected", "Number of RSL links connected", "", 16, 0 }, + { "lchan_borken", "Number of lchans in the BORKEN state", "", 16, 0 }, + { "ts_borken", "Number of timeslots in the BORKEN state", "", 16, 0 }, }; static const struct osmo_stat_item_group_desc bts_statg_desc = { diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c index fc8cd3fd8..ad37e9e07 100644 --- a/src/osmo-bsc/lchan_fsm.c +++ b/src/osmo-bsc/lchan_fsm.c @@ -1071,6 +1071,28 @@ static void lchan_fsm_wait_rf_release_ack(struct osmo_fsm_inst *fi, uint32_t eve static void lchan_fsm_borken_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) { struct gsm_lchan *lchan = lchan_fi_lchan(fi); + enum bts_counter_id ctr; + switch (prev_state) { + case LCHAN_ST_UNUSED: + ctr = BTS_CTR_LCHAN_BORKEN_FROM_UNUSED; + break; + case LCHAN_ST_WAIT_ACTIV_ACK: + ctr = BTS_CTR_LCHAN_BORKEN_FROM_WAIT_ACTIV_ACK; + break; + case LCHAN_ST_WAIT_RF_RELEASE_ACK: + ctr = BTS_CTR_LCHAN_BORKEN_FROM_WAIT_RF_RELEASE_ACK; + break; + case LCHAN_ST_BORKEN: + ctr = BTS_CTR_LCHAN_BORKEN_FROM_BORKEN; + break; + default: + ctr = BTS_CTR_LCHAN_BORKEN_FROM_UNKNOWN; + } + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[ctr]); + if (prev_state != LCHAN_ST_BORKEN) + osmo_stat_item_inc(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1); + + /* The actual action besides all the beancounting above */ lchan_reset(lchan); } @@ -1081,6 +1103,8 @@ static void lchan_fsm_borken(struct osmo_fsm_inst *fi, uint32_t event, void *dat case LCHAN_EV_RSL_CHAN_ACTIV_ACK: /* A late Chan Activ ACK? Release. */ + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_ACK]); + osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1); lchan->release.in_error = true; lchan->release.rsl_error_cause = RSL_ERR_INTERWORKING; lchan_fsm_state_chg(LCHAN_ST_WAIT_RF_RELEASE_ACK); @@ -1088,11 +1112,15 @@ static void lchan_fsm_borken(struct osmo_fsm_inst *fi, uint32_t event, void *dat case LCHAN_EV_RSL_CHAN_ACTIV_NACK: /* A late Chan Activ NACK? Ok then, unused. */ + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_CHAN_ACTIV_NACK]); + osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1); lchan_fsm_state_chg(LCHAN_ST_UNUSED); return; case LCHAN_EV_RSL_RF_CHAN_REL_ACK: /* A late Release ACK? */ + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_RF_CHAN_REL_ACK]); + osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1); lchan->release.in_error = true; lchan->release.rsl_error_cause = RSL_ERR_INTERWORKING; lchan_fsm_state_chg(LCHAN_ST_WAIT_AFTER_ERROR); @@ -1384,6 +1412,10 @@ exit_release_handler: void lchan_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) { struct gsm_lchan *lchan = lchan_fi_lchan(fi); + if (lchan->fi->state == LCHAN_ST_BORKEN) { + rate_ctr_inc(&lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_LCHAN_BORKEN_EV_CLEANUP]); + osmo_stat_item_dec(lchan->ts->trx->bts->bts_statg->items[BTS_STAT_LCHAN_BORKEN], 1); + } lchan_reset(lchan); if (lchan->last_error) { talloc_free(lchan->last_error); diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index ddebb6a7d..0d6127258 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -1006,6 +1006,66 @@ reject: return -EINVAL; } +/* Handle Confusion message, MSC indicating an error to us: + * + * See 3GPP TS 48.008 ยง3.2.1.45 + */ +static int bssmap_handle_confusion(struct gsm_subscriber_connection *conn, + struct msgb *msg, unsigned int length) +{ + struct tlv_parsed tp; + int diag_len; + enum gsm0808_cause cause; + enum gsm0808_cause_class cause_class; + struct gsm0808_diagnostics *diag; + + osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1); + + /* Check for the Cause and Diagnostic mandatory elements */ + if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE) || !TLVP_PRESENT(&tp, GSM0808_IE_DIAGNOSTIC)) { + LOGPFSML(conn->fi, LOGL_ERROR, + "Received Confusion message," + " but either Cause or Diagnostic mandatory IE is not present: %s\n", + osmo_hexdump(msg->l4h, length)); + return -EINVAL; + } + + diag_len = TLVP_LEN(&tp, GSM0808_IE_DIAGNOSTIC); + if (diag_len < 5) { + LOGPFSML(conn->fi, LOGL_ERROR, + "Received Confusion message with short Diagnostic length: %d (expected > 5)\n", + diag_len); + return -EINVAL; + } + + cause = gsm0808_get_cause(&tp); + cause_class = gsm0808_cause_class(cause); + LOGPFSML(conn->fi, LOGL_ERROR, + "Received Confusion message: Cause %d/0x%x (%s)", + cause, cause, gsm0808_cause_name(cause)); + LOGPFSML(conn->fi, LOGL_ERROR, + "Received Confusion message: Cause class %d/0x%x (%s)", + cause_class, cause_class, gsm0808_cause_class_name(cause_class)); + + diag = (struct gsm0808_diagnostics *)TLVP_VAL(&tp, GSM0808_IE_DIAGNOSTIC); + /* octet location */ + LOGPFSML(conn->fi, LOGL_ERROR, + " Confusion Diagnostics error octet location %d (%s)\n", + diag->error_pointer_octet, + gsm0808_diagnostics_octet_location_str(diag->error_pointer_octet)); + /* bit location */ + LOGPFSML(conn->fi, LOGL_ERROR, + " Confusion Diagnostics error bit location: %d (%s)\n", + diag->error_pointer_bit, + gsm0808_diagnostics_bit_location_str(diag->error_pointer_bit)); + /* received message dump */ + LOGPFSML(conn->fi, LOGL_ERROR, + " Confusion Diagnostics message that provoked the error: %s\n", + osmo_hexdump(diag->msg, diag_len-2)); + + return 0; +} + static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length) { @@ -1082,6 +1142,10 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn, rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_CLASSMARK_RQST]); ret = gsm48_send_rr_classmark_enquiry(conn->lchan); break; + case BSS_MAP_MSG_CONFUSION: + rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_CONFUSION]); + ret = bssmap_handle_confusion(conn, msg, length); + break; default: rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UNKNOWN]); LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n", diff --git a/src/osmo-bsc/osmo_bsc_filter.c b/src/osmo-bsc/osmo_bsc_filter.c index 332ba6b83..3b72aeeb9 100644 --- a/src/osmo-bsc/osmo_bsc_filter.c +++ b/src/osmo-bsc/osmo_bsc_filter.c @@ -45,7 +45,6 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn, { struct tlv_parsed tp; int parse_res; - struct gsm_bts *bts = conn_get_bts(conn); int tzunits; uint8_t tzbsd = 0; uint8_t dst = 0; @@ -58,7 +57,7 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn, return 0; /* Is TZ patching enabled? */ - struct gsm_tz *tz = &bts->network->tz; + struct gsm_tz *tz = &conn->network->tz; if (!tz->override) return 0; diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c index db3ffe4e7..e58ff7faf 100644 --- a/src/osmo-bsc/osmo_bsc_msc.c +++ b/src/osmo-bsc/osmo_bsc_msc.c @@ -55,6 +55,7 @@ static const struct rate_ctr_desc msc_ctr_description[] = { [MSC_CTR_BSSMAP_RX_DT1_LCLS_CONNECT_CTRL] = {"bssmap:rx:dt1:lcls_connect_ctrl:cmd", "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_CONFUSION] = {"bssmap:rx:dt1:confusion", "Number of received BSSMAP DT1 CONFUSION messages"}, [MSC_CTR_BSSMAP_RX_DT1_UNKNOWN] = {"bssmap:rx:dt1:err_unknown", "Number of received BSSMAP unknown DT1 messages"}, [MSC_CTR_BSSMAP_RX_DT1_DTAP] = {"bssmap:rx:dt1:dtap:good", "Number of received BSSMAP DTAP messages"}, [MSC_CTR_BSSMAP_RX_DT1_DTAP_ERROR] = {"bssmap:rx:dt1:dtap:error", "Number of received BSSMAP DTAP messages with errors"}, diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c index f8adfb6c7..a72833f82 100644 --- a/src/osmo-bsc/timeslot_fsm.c +++ b/src/osmo-bsc/timeslot_fsm.c @@ -654,6 +654,39 @@ static void ts_fsm_in_use(struct osmo_fsm_inst *fi, uint32_t event, void *data) } } +static void ts_fsm_borken_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct gsm_bts_trx_ts *ts = ts_fi_ts(fi); + enum bts_counter_id ctr; + switch (prev_state) { + case TS_ST_NOT_INITIALIZED: + ctr = BTS_CTR_TS_BORKEN_FROM_NOT_INITIALIZED; + break; + case TS_ST_UNUSED: + ctr = BTS_CTR_TS_BORKEN_FROM_UNUSED; + break; + case TS_ST_WAIT_PDCH_ACT: + ctr = BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_ACT; + break; + case TS_ST_PDCH: + ctr = BTS_CTR_TS_BORKEN_FROM_PDCH; + break; + case TS_ST_WAIT_PDCH_DEACT: + ctr = BTS_CTR_TS_BORKEN_FROM_WAIT_PDCH_DEACT; + break; + case TS_ST_IN_USE: + ctr = BTS_CTR_TS_BORKEN_FROM_IN_USE; + break; + case TS_ST_BORKEN: + ctr = BTS_CTR_TS_BORKEN_FROM_BORKEN; + break; + default: + ctr = BTS_CTR_TS_BORKEN_FROM_UNKNOWN; + } + rate_ctr_inc(&ts->trx->bts->bts_ctrs->ctr[ctr]); + osmo_stat_item_inc(ts->trx->bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1); +} + static void ts_fsm_borken(struct osmo_fsm_inst *fi, uint32_t event, void *data) { switch (event) { @@ -669,10 +702,30 @@ static void ts_fsm_borken(struct osmo_fsm_inst *fi, uint32_t event, void *data) } case TS_EV_PDCH_ACT_ACK: - /* Late PDCH activation ACK is not a crime. - * Just go into the PDCH mode as normal. */ - osmo_fsm_inst_state_chg(fi, TS_ST_PDCH, 0, 0); - return; + case TS_EV_PDCH_ACT_NACK: + { + struct gsm_bts_trx_ts *ts = ts_fi_ts(fi); + struct gsm_bts *bts = ts->trx->bts; + /* Late PDCH activation ACK/NACK is not a crime. + * Just process them as normal. */ + rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_PDCH_ACT_ACK_NACK]); + osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1); + ts_fsm_wait_pdch_act(fi, event, data); + return; + } + + case TS_EV_PDCH_DEACT_ACK: + case TS_EV_PDCH_DEACT_NACK: + { + struct gsm_bts_trx_ts *ts = ts_fi_ts(fi); + struct gsm_bts *bts = ts->trx->bts; + /* Late PDCH deactivation ACK/NACK is also not a crime. + * Just process them as normal. */ + rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_PDCH_DEACT_ACK_NACK]); + osmo_stat_item_dec(bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1); + ts_fsm_wait_pdch_deact(fi, event, data); + return; + } default: OSMO_ASSERT(false); @@ -725,6 +778,15 @@ static void ts_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data } } +static void ts_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) +{ + struct gsm_bts_trx_ts *ts = ts_fi_ts(fi); + if (ts->fi->state == TS_ST_BORKEN) { + rate_ctr_inc(&ts->trx->bts->bts_ctrs->ctr[BTS_CTR_TS_BORKEN_EV_CLEANUP]); + osmo_stat_item_dec(ts->trx->bts->bts_statg->items[BTS_STAT_TS_BORKEN], 1); + } +} + #define S(x) (1 << (x)) static const struct osmo_fsm_state ts_fsm_states[] = { @@ -822,13 +884,19 @@ static const struct osmo_fsm_state ts_fsm_states[] = { }, [TS_ST_BORKEN] = { .name = "BORKEN", + .onenter = ts_fsm_borken_onenter, .action = ts_fsm_borken, .in_event_mask = 0 | S(TS_EV_LCHAN_REQUESTED) | S(TS_EV_LCHAN_UNUSED) | S(TS_EV_PDCH_ACT_ACK) + | S(TS_EV_PDCH_ACT_NACK) + | S(TS_EV_PDCH_DEACT_ACK) + | S(TS_EV_PDCH_DEACT_NACK) , .out_state_mask = 0 + | S(TS_ST_IN_USE) + | S(TS_ST_UNUSED) | S(TS_ST_NOT_INITIALIZED) | S(TS_ST_PDCH) , @@ -862,6 +930,7 @@ static struct osmo_fsm ts_fsm = { | S(TS_EV_RSL_DOWN) , .allstate_action = ts_fsm_allstate, + .cleanup = ts_fsm_cleanup, }; /* Return true if any lchans are waiting for this timeslot to become a specific PCHAN. If target_pchan is diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c index 6079ec500..5d8711838 100644 --- a/tests/bsc/bsc_test.c +++ b/tests/bsc/bsc_test.c @@ -123,16 +123,9 @@ static void test_scan(void) int i; struct gsm_network *net = gsm_network_init(ctx); - struct gsm_bts *bts = gsm_bts_alloc(net, 0); - struct bsc_msc_data *msc; - struct gsm_subscriber_connection *conn; + struct gsm_subscriber_connection *conn = talloc_zero(net, struct gsm_subscriber_connection); - msc = talloc_zero(net, struct bsc_msc_data); - conn = talloc_zero(net, struct gsm_subscriber_connection); - - bts->network = net; - conn->sccp.msc = msc; - conn->lchan = &bts->c0->ts[1].lchan[0]; + conn->network = net; /* start testing with proper messages */ printf("Testing BTS<->MSC message scan.\n"); |