diff options
Diffstat (limited to 'src/osmo-bsc/abis_om2000.c')
-rw-r--r-- | src/osmo-bsc/abis_om2000.c | 289 |
1 files changed, 251 insertions, 38 deletions
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) |