om2k: Add option to limit OML version during negotiation

Starting from G12R13 the MCTR swiches to BSC controlled mode. And
although we think we know how to configure it (via MCTR Conf Req),
something doesn't work right and the timeslot configuration is not
accepted. (TS Conf Result shows "Data not according to request").

So as a workaround for now, we use this version of the protocol where
we don't configure the MCTR (it's in "BTS controlled mode") and with
this protocol, the BTS accepts our timeslot config and we can bring
the system up.

This commit add a generic option to limit either OML or RSL IWD
version to any value. It also keeps track of the actual negotation
version so we can react to it in other places of the code.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Change-Id: I8f0b0ba72056ea4250fe490e7a38630c77c04f65

better version limit

Change-Id: Ia789f8ede3eab7eeca6c759da0109e0b53398f60
This commit is contained in:
Sylvain Munaut 2020-05-05 21:07:58 +02:00
parent ce0b562785
commit dbd1b50604
3 changed files with 91 additions and 8 deletions

View File

@ -1135,6 +1135,10 @@ struct gsm_bts {
struct gsm_abis_mo mo;
} tf;
uint32_t use_superchannel:1;
struct {
uint16_t limit;
uint16_t active;
} om2k_version[16];
} rbs2000;
struct {
uint8_t bts_type;

View File

@ -2447,8 +2447,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 {
@ -2459,11 +2459,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;
@ -2494,25 +2496,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);
}

View File

@ -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);