WIP: OM2000: Full state machine implementation using osmo_fsm

Our existing OM2000 code for initializing all Managed Objects of a BTS
at startup was never complete.  Rather than trying to fix the old-style
code, introudce a hierarchy of osmo_fsm's reflecting the full protocol
hand-shake and sequence of bringing up the individual MO's.

If this works out well, it mihgt make sense to convert the TS 12.21 OML
code for other BTS models, too.

Change-Id: I3e11b28ba22b8c227e0401e6207fdda5381dda8c
This commit is contained in:
Harald Welte 2016-07-09 22:20:57 +02:00
parent b748012d31
commit 591e1d7daa
4 changed files with 1132 additions and 286 deletions

View File

@ -41,13 +41,6 @@ enum om2k_mo_state {
OM2K_MO_S_DISABLED,
};
struct abis_om2k_mo {
uint8_t class;
uint8_t bts;
uint8_t assoc_so;
uint8_t inst;
} __attribute__ ((packed));
/* on-wire format for IS conn group */
struct om2k_is_conn_grp {
uint16_t icp1;
@ -90,6 +83,10 @@ int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx);
int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts);
struct osmo_fsm_inst *om2k_bts_fsm_start(struct gsm_bts *bts);
void abis_om2k_bts_init(struct gsm_bts *bts);
void abis_om2k_trx_init(struct gsm_bts_trx *trx);
int abis_om2k_vty_init(void);
struct vty;

View File

@ -104,6 +104,19 @@ struct gsm_abis_mo {
struct gsm_bts *bts;
};
/* Ericsson OM2000 Managed Object */
struct abis_om2k_mo {
uint8_t class;
uint8_t bts;
uint8_t assoc_so;
uint8_t inst;
} __attribute__ ((packed));
struct om2k_mo {
struct abis_om2k_mo addr;
struct osmo_fsm_inst *fsm;
};
#define MAX_A5_KEY_LEN (128/8)
#define A38_XOR_MIN_KEY_LEN 12
#define A38_XOR_MAX_KEY_LEN 16
@ -387,6 +400,12 @@ struct gsm_bts_trx_ts {
/* To which E1 subslot are we connected */
struct gsm_e1_subslot e1_link;
union {
struct {
struct om2k_mo om2k_mo;
} rbs2000;
};
struct gsm_lchan lchan[TS_MAX_LCHAN];
};
@ -441,6 +460,17 @@ struct gsm_bts_trx {
uint8_t test_nr;
struct rxlev_stats rxlev_stat;
} ipaccess;
struct {
struct {
struct om2k_mo om2k_mo;
} trxc;
struct {
struct om2k_mo om2k_mo;
} rx;
struct {
struct om2k_mo om2k_mo;
} tx;
} rbs2000;
};
struct gsm_bts_trx_ts ts[TRX_NR_TS];
};
@ -679,17 +709,26 @@ struct gsm_bts {
} bs11;
struct {
struct {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
struct llist_head conn_groups;
} cf;
struct {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
struct llist_head conn_groups;
} is;
struct {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
struct llist_head conn_groups;
} con;
struct {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
} dp;
struct {
struct om2k_mo om2k_mo;
struct gsm_abis_mo mo;
} tf;
} rbs2000;

File diff suppressed because it is too large Load Diff

View File

@ -34,18 +34,20 @@
static void bootstrap_om_bts(struct gsm_bts *bts)
{
LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
abis_om2k_tx_start_req(bts, &om2k_mo_cf);
/* FIXME */
/* FIXME: this is global init, not bootstrapping */
abis_om2k_bts_init(bts);
abis_om2k_trx_init(bts->c0);
/* TODO: Should we wait for a Failure report? */
om2k_bts_fsm_start(bts);
}
static void bootstrap_om_trx(struct gsm_bts_trx *trx)
{
struct abis_om2k_mo trx_mo = { OM2K_MO_CLS_TRXC, 0, 255, trx->nr };
LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
trx->bts->nr, trx->nr);
abis_om2k_tx_reset_cmd(trx->bts, &trx_mo);
/* FIXME */
}
static int shutdown_om(struct gsm_bts *bts)
@ -137,103 +139,6 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
static void nm_statechg_evt(unsigned int signal,
struct nm_statechg_signal_data *nsd)
{
struct abis_om2k_mo mo;
if (nsd->bts->type != GSM_BTS_TYPE_RBS2000)
return;
switch (nsd->om2k_mo->class) {
case OM2K_MO_CLS_CF:
if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
nsd->new_state->availability != OM2K_MO_S_STARTED)
break;
/* CF has started, we can trigger IS and TF start */
abis_om2k_tx_connect_cmd(nsd->bts, &om2k_mo_is);
abis_om2k_tx_connect_cmd(nsd->bts, &om2k_mo_tf);
break;
case OM2K_MO_CLS_IS:
if (nsd->new_state->availability == OM2K_MO_S_ENABLED) {
/* IS is enabled, we can proceed with TRXC/RX/TX/TS */
break;
}
if (nsd->new_state->operational != NM_OPSTATE_ENABLED)
break;
/* IS has started, we can configure + enable it */
abis_om2k_tx_is_conf_req(nsd->bts);
break;
case OM2K_MO_CLS_TF:
if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
nsd->new_state->availability == OM2K_MO_S_DISABLED)
break;
if (nsd->new_state->availability == OM2K_MO_S_STARTED) {
/* TF has started, configure + enable it */
abis_om2k_tx_tf_conf_req(nsd->bts);
}
break;
case OM2K_MO_CLS_TRXC:
if (nsd->new_state->availability != OM2K_MO_S_STARTED)
break;
/* TRXC is started, connect the TX and RX objects */
memcpy(&mo, nsd->om2k_mo, sizeof(mo));
mo.class = OM2K_MO_CLS_TX;
abis_om2k_tx_connect_cmd(nsd->bts, &mo);
mo.class = OM2K_MO_CLS_RX;
abis_om2k_tx_connect_cmd(nsd->bts, &mo);
break;
case OM2K_MO_CLS_RX:
if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
nsd->new_state->availability != OM2K_MO_S_STARTED)
break;
/* RX is started, configure + enable it */
abis_om2k_tx_rx_conf_req(nsd->obj);
break;
case OM2K_MO_CLS_TX:
if (nsd->new_state->operational != NM_OPSTATE_ENABLED ||
nsd->new_state->availability != OM2K_MO_S_STARTED)
break;
/* RX is started, configure + enable it */
abis_om2k_tx_tx_conf_req(nsd->obj);
break;
}
}
static void nm_conf_res(struct nm_om2k_signal_data *nsd)
{
switch (nsd->om2k_mo->class) {
case OM2K_MO_CLS_IS:
case OM2K_MO_CLS_TF:
case OM2K_MO_CLS_RX:
case OM2K_MO_CLS_TX:
/* If configuration was a success, enable it */
abis_om2k_tx_enable_req(nsd->bts, nsd->om2k_mo);
break;
}
}
static int nm_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
if (subsys != SS_NM)
return 0;
switch (signal) {
case S_NM_STATECHG_OPER:
case S_NM_STATECHG_ADM:
nm_statechg_evt(signal, signal_data);
break;
case S_NM_OM2K_CONF_RES:
nm_conf_res(signal_data);
break;
default:
break;
}
return 0;
}
static void config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
abis_om2k_config_write_bts(vty, bts);
@ -266,7 +171,6 @@ static int bts_model_rbs2k_start(struct gsm_network *net)
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
return 0;
}