aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libbsc
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-11-11 19:41:59 +0100
committerHarald Welte <laforge@gnumonks.org>2016-11-13 21:22:29 +0100
commiteae68292bdd3906950260ac307081af4b3acf3e5 (patch)
tree64cdf96a013125db0f7f59c6c5fe836338501c2f /openbsc/src/libbsc
parentfe7be8ddd0563ee98ca2ee9879983384d2491306 (diff)
Support configuration of CON MO Groups/Paths from VTY
The code for supporting the configuration of the OM2000 CON (LAPD Concentrator) MO was so far incomplete and not used from the OM2000 FSM initialization. This patch adds * VTY commands for configuration of CON Groups and Paths * The FSM integration to actually configure the CON MO Change-Id: I56dc1b5e35adef3a2078bcf9536537eb0f454192
Diffstat (limited to 'openbsc/src/libbsc')
-rw-r--r--openbsc/src/libbsc/abis_om2000.c71
-rw-r--r--openbsc/src/libbsc/abis_om2000_vty.c189
2 files changed, 191 insertions, 69 deletions
diff --git a/openbsc/src/libbsc/abis_om2000.c b/openbsc/src/libbsc/abis_om2000.c
index 8c4bfb3b5..2733a90fd 100644
--- a/openbsc/src/libbsc/abis_om2000.c
+++ b/openbsc/src/libbsc/abis_om2000.c
@@ -1132,20 +1132,48 @@ int abis_om2k_tx_is_conf_req(struct gsm_bts *bts)
return abis_om2k_sendmsg(bts, msg);
}
-int abis_om2k_tx_con_conf_req(struct gsm_bts *bts, uint8_t *data,
- unsigned int len)
+int abis_om2k_tx_con_conf_req(struct gsm_bts *bts)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
+ struct con_group *grp;
+ unsigned int num_grps = 0;
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr,
- OM2K_MSGT_CON_CONF_REQ);
+ /* count number of groups in linked list */
+ llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list)
+ num_grps++;
- msgb_tv_put(msg, OM2K_DEI_LIST_NR, 1);
- msgb_tv_put(msg, OM2K_DEI_END_LIST_NR, 1);
+ if (!num_grps)
+ return -EINVAL;
+
+ /* first build the value part of the OM2K_DEI_CON_CONN_LIST DEI */
+ msgb_put_u8(msg, num_grps);
+ llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list) {
+ struct con_path *cp;
+ unsigned int num_paths = 0;
+ llist_for_each_entry(cp, &grp->paths, list)
+ num_paths++;
+ msgb_put_u8(msg, num_paths);
+ llist_for_each_entry(cp, &grp->paths, list) {
+ struct om2k_con_path *om2k_cp;
+ om2k_cp = (struct om2k_con_path *) msgb_put(msg, sizeof(*om2k_cp));
+ om2k_cp->ccp = htons(cp->ccp);
+ om2k_cp->ci = cp->ci;
+ om2k_cp->tag = cp->tag;
+ om2k_cp->tei = cp->tei;
+ }
+ }
+ msgb_push_u8(msg, msgb_length(msg));
+ msgb_push_u8(msg, OM2K_DEI_CON_CONN_LIST);
+
+ /* pre-pend the list number DEIs */
+ msgb_tv_push(msg, OM2K_DEI_END_LIST_NR, 1);
+ msgb_tv_push(msg, OM2K_DEI_LIST_NR, 1);
- msgb_tlv_put(msg, OM2K_DEI_CON_CONN_LIST, len, data);
+ /* pre-pend the OM2K header */
+ o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k));
+ fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr,
+ OM2K_MSGT_CON_CONF_REQ);
DEBUGP(DNM, "Tx MO=%s %s\n",
om2k_mo_name(&bts->rbs2000.con.om2k_mo.addr),
@@ -1566,8 +1594,7 @@ static void om2k_mo_st_wait_start_res(struct osmo_fsm_inst *fi, uint32_t event,
abis_om2k_tx_is_conf_req(omfp->trx->bts);
break;
case OM2K_MO_CLS_CON:
- /* TODO */
- //abis_om2k_tx_con_conf_req(omfp->trx->bts, data, len);
+ abis_om2k_tx_con_conf_req(omfp->trx->bts);
break;
case OM2K_MO_CLS_TX:
abis_om2k_tx_tx_conf_req(omfp->trx);
@@ -2061,6 +2088,7 @@ enum om2k_bts_event {
OM2K_BTS_EVT_START,
OM2K_BTS_EVT_CF_DONE,
OM2K_BTS_EVT_IS_DONE,
+ OM2K_BTS_EVT_CON_DONE,
OM2K_BTS_EVT_TF_DONE,
OM2K_BTS_EVT_TRX_DONE,
OM2K_BTS_EVT_STOP,
@@ -2070,6 +2098,7 @@ static const struct value_string om2k_bts_events[] = {
{ OM2K_BTS_EVT_START, "START" },
{ OM2K_BTS_EVT_CF_DONE, "CF-DONE" },
{ OM2K_BTS_EVT_IS_DONE, "IS-DONE" },
+ { OM2K_BTS_EVT_CON_DONE, "CON-DONE" },
{ OM2K_BTS_EVT_TF_DONE, "TF-DONE" },
{ OM2K_BTS_EVT_TRX_DONE, "TRX-DONE" },
{ OM2K_BTS_EVT_STOP, "STOP" },
@@ -2080,6 +2109,7 @@ enum om2k_bts_state {
OM2K_BTS_S_INIT,
OM2K_BTS_S_WAIT_CF,
OM2K_BTS_S_WAIT_IS,
+ OM2K_BTS_S_WAIT_CON,
OM2K_BTS_S_WAIT_TF,
OM2K_BTS_S_WAIT_TRX,
OM2K_BTS_S_DONE,
@@ -2121,6 +2151,18 @@ static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *d
struct gsm_bts *bts = obfp->bts;
OSMO_ASSERT(event == OM2K_BTS_EVT_IS_DONE);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON,
+ BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CON_DONE, bts->c0,
+ &bts->rbs2000.con.om2k_mo);
+}
+
+static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct om2k_bts_fsm_priv *obfp = fi->priv;
+ struct gsm_bts *bts = obfp->bts;
+
+ OSMO_ASSERT(event == OM2K_BTS_EVT_CON_DONE);
/* TF can take a long time to initialize, wait for 10min */
osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TF, 600, 0);
om2k_mo_fsm_start(fi, OM2K_BTS_EVT_TF_DONE, bts->c0,
@@ -2178,10 +2220,17 @@ 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_TF),
+ S(OM2K_BTS_S_WAIT_CON),
.name = "WAIT-IS",
.action = om2k_bts_s_wait_is,
},
+ [OM2K_BTS_S_WAIT_CON] = {
+ .in_event_mask = S(OM2K_BTS_EVT_CON_DONE),
+ .out_state_mask = S(OM2K_BTS_S_ERROR) |
+ S(OM2K_BTS_S_WAIT_TF),
+ .name = "WAIT-CON",
+ .action = om2k_bts_s_wait_con,
+ },
[OM2K_BTS_S_WAIT_TF] = {
.in_event_mask = S(OM2K_BTS_EVT_TF_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
diff --git a/openbsc/src/libbsc/abis_om2000_vty.c b/openbsc/src/libbsc/abis_om2000_vty.c
index 64d205cee..2a89d4991 100644
--- a/openbsc/src/libbsc/abis_om2000_vty.c
+++ b/openbsc/src/libbsc/abis_om2000_vty.c
@@ -48,9 +48,18 @@ static struct cmd_node om2k_node = {
1,
};
+static struct cmd_node om2k_con_group_node = {
+ OM2K_CON_GROUP_NODE,
+ "%s(om2k-con-group)# ",
+ 1,
+};
+
+struct con_group;
+
struct oml_node_state {
struct gsm_bts *bts;
struct abis_om2k_mo mo;
+ struct con_group *cg;
};
static int dummy_config_write(struct vty *v)
@@ -246,65 +255,113 @@ DEFUN(om2k_cap_req, om2k_cap_req_cmd,
return CMD_SUCCESS;
}
+static struct con_group *con_group_find_or_create(struct gsm_bts *bts, uint8_t cg)
+{
+ struct con_group *ent;
-struct con_conn_group {
- struct llist_head list;
+ llist_for_each_entry(ent, &bts->rbs2000.con.conn_groups, list) {
+ if (ent->cg == cg)
+ return ent;
+ }
- uint8_t cg;
- uint16_t ccp;
- uint8_t tag;
- uint8_t tei;
-};
+ ent = talloc_zero(bts, struct con_group);
+ ent->bts = bts;
+ ent->cg = cg;
+ INIT_LLIST_HEAD(&ent->paths);
+ llist_add_tail(&ent->list, &bts->rbs2000.con.conn_groups);
-static void add_con_list(struct gsm_bts *bts, uint8_t cg, uint16_t ccp,
- uint8_t tag, uint8_t tei)
-{
- struct con_conn_group *ent = talloc_zero(bts, struct con_conn_group);
+ return ent;
+}
- ent->cg = cg;
- ent->ccp = ccp;
- ent->tag = tag;
- ent->tei = tei;
+static int con_group_del(struct gsm_bts *bts, uint8_t cg_id)
+{
+ struct con_group *cg, *cg2;
- llist_add_tail(&ent->list, &bts->rbs2000.con.conn_groups);
+ llist_for_each_entry_safe(cg, cg2, &bts->rbs2000.con.conn_groups, list) {
+ if (cg->cg == cg_id) {
+ llist_del(&cg->list);
+ talloc_free(cg);
+ return 0;
+ };
+ }
+ return -ENOENT;
}
-static int del_con_list(struct gsm_bts *bts, uint8_t cg, uint16_t ccp,
- uint8_t tag, uint8_t tei)
+static void con_group_add_path(struct con_group *cg, uint16_t ccp,
+ uint8_t ci, uint8_t tag, uint8_t tei)
{
- struct con_conn_group *grp, *grp2;
+ struct con_path *cp = talloc_zero(cg, struct con_path);
- llist_for_each_entry_safe(grp, grp2, &bts->rbs2000.con.conn_groups, list) {
- if (grp->cg == cg && grp->ccp == ccp && grp->tag == tag
- && grp->tei == tei) {
- llist_del(&grp->list);
- talloc_free(grp);
+ cp->ccp = ccp;
+ cp->ci = ci;
+ cp->tag = tag;
+ cp->tei = tei;
+ llist_add(&cp->list, &cg->paths);
+}
+
+static int con_group_del_path(struct con_group *cg, uint16_t ccp,
+ uint8_t ci, uint8_t tag, uint8_t tei)
+{
+ struct con_path *cp, *cp2;
+ llist_for_each_entry_safe(cp, cp2, &cg->paths, list) {
+ if (cp->ccp == ccp && cp->ci == ci && cp->tag == tag &&
+ cp->tei == tei) {
+ llist_del(&cp->list);
+ talloc_free(cp);
return 0;
}
}
return -ENOENT;
}
-#define CON_LIST_HELP "CON connetiton list\n" \
- "Add entry to CON list\n" \
- "Delete entry from CON list\n" \
- "Connection Group Number\n" \
- "CON Connection Point\n" \
+DEFUN(cfg_om2k_con_group, cfg_om2k_con_group_cmd,
+ "con-connection-group <1-31>",
+ "Configure a CON (Concentrator) Connection Group\n"
+ "CON Connection Group Number\n")
+{
+ struct gsm_bts *bts = vty->index;
+ struct con_group *cg;
+ uint8_t cgid = atoi(argv[0]);
+
+ if (bts->type != GSM_BTS_TYPE_RBS2000) {
+ vty_out(vty, "%% CON MO only exists in RBS2000%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
-DEFUN(om2k_con_list_dec, om2k_con_list_dec_cmd,
- "con-connection-list (add|del) <1-255> <0-1023> deconcentrated",
- CON_LIST_HELP "De-concentrated in/outlet\n")
+ cg = con_group_find_or_create(bts, cgid);
+ if (!cg) {
+ vty_out(vty, "%% Cannot create CON Group%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty->node = OM2K_CON_GROUP_NODE;
+ vty->index = cg;
+
+ return CMD_SUCCESS;
+}
+
+#define CON_PATH_HELP "CON Path (In/Out)\n" \
+ "Add CON Path to Concentration Group\n" \
+ "Delete CON Path from Concentration Group\n" \
+ "CON Conection Point\n" \
+ "Contiguity Index\n" \
+
+DEFUN(cfg_om2k_con_path_dec, cfg_om2k_con_path_dec_cmd,
+ "con-path (add|del) <0-1023> <0-7> deconcentrated <0-63>",
+ CON_PATH_HELP "De-concentrated in/outlet\n" "TEI Value\n")
{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- uint8_t cg = atoi(argv[1]);
- uint16_t ccp = atoi(argv[2]);
+ struct con_group *cg = vty->index;
+ uint16_t ccp = atoi(argv[1]);
+ uint8_t ci = atoi(argv[2]);
+ uint8_t tei = atoi(argv[3]);
if (!strcmp(argv[0], "add"))
- add_con_list(bts, cg, ccp, 0, 0xff);
+ con_group_add_path(cg, ccp, ci, 0, tei);
else {
- if (del_con_list(bts, cg, ccp, 0, 0xff) < 0) {
- vty_out(vty, "%% No matching CON list entry%s",
+ if (con_group_del_path(cg, ccp, ci, 0, tei) < 0) {
+ vty_out(vty, "%% No matching CON Path%s",
VTY_NEWLINE);
return CMD_WARNING;
}
@@ -313,20 +370,19 @@ DEFUN(om2k_con_list_dec, om2k_con_list_dec_cmd,
return CMD_SUCCESS;
}
-DEFUN(om2k_con_list_tei, om2k_con_list_tei_cmd,
- "con-connection-list (add|del) <1-255> <0-1023> tei <0-63>",
- CON_LIST_HELP "Concentrated in/outlet with TEI\n" "TEI Number\n")
+DEFUN(cfg_om2k_con_path_conc, cfg_om2k_con_path_conc_cmd,
+ "con-path (add|del) <0-1023> <0-7> concentrated <1-16>",
+ CON_PATH_HELP "Concentrated in/outlet\n" "Tag Number\n")
{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- uint8_t cg = atoi(argv[1]);
- uint16_t ccp = atoi(argv[2]);
- uint8_t tei = atoi(argv[3]);
+ struct con_group *cg = vty->index;
+ uint16_t ccp = atoi(argv[1]);
+ uint8_t ci = atoi(argv[2]);
+ uint8_t tag = atoi(argv[3]);
if (!strcmp(argv[0], "add"))
- add_con_list(bts, cg, ccp, cg, tei);
+ con_group_add_path(cg, ccp, ci, tag, 0xff);
else {
- if (del_con_list(bts, cg, ccp, cg, tei) < 0) {
+ if (con_group_del_path(cg, ccp, ci, tag, 0xff) < 0) {
vty_out(vty, "%% No matching CON list entry%s",
VTY_NEWLINE);
return CMD_WARNING;
@@ -437,22 +493,35 @@ DEFUN(om2k_conf_req, om2k_conf_req_cmd,
return CMD_SUCCESS;
}
+static void dump_con_group(struct vty *vty, struct con_group *cg)
+{
+ struct con_path *cp;
+
+ llist_for_each_entry(cp, &cg->paths, list) {
+ vty_out(vty, " con-path add %u %u ", cp->ccp, cp->ci);
+ if (cp->tei == 0xff) {
+ vty_out(vty, "concentrated %u%s", cp->tag,
+ VTY_NEWLINE);
+ } else {
+ vty_out(vty, "deconcentrated %u%s", cp->tei,
+ VTY_NEWLINE);
+ }
+ }
+}
+
void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
{
struct is_conn_group *igrp;
- struct con_conn_group *cgrp;
+ struct con_group *cgrp;
llist_for_each_entry(igrp, &bts->rbs2000.is.conn_groups, list)
vty_out(vty, " is-connection-list add %u %u %u%s",
igrp->icp1, igrp->icp2, igrp->ci, VTY_NEWLINE);
llist_for_each_entry(cgrp, &bts->rbs2000.con.conn_groups, list) {
- vty_out(vty, " con-connection-list add %u %u ",
- cgrp->cg, cgrp->ccp);
- if (cgrp->tei == 0xff)
- vty_out(vty, "deconcentrated%s", VTY_NEWLINE);
- else
- vty_out(vty, "tei %u%s", cgrp->tei, VTY_NEWLINE);
+ vty_out(vty, " con-connection-group %u%s", cgrp->cg,
+ VTY_NEWLINE);
+ dump_con_group(vty, cgrp);
}
}
@@ -474,10 +543,14 @@ int abis_om2k_vty_init(void)
install_element(OM2K_NODE, &om2k_test_cmd);
install_element(OM2K_NODE, &om2k_cap_req_cmd);
install_element(OM2K_NODE, &om2k_conf_req_cmd);
- install_element(OM2K_NODE, &om2k_con_list_dec_cmd);
- install_element(OM2K_NODE, &om2k_con_list_tei_cmd);
+
+ install_node(&om2k_con_group_node, dummy_config_write);
+ vty_install_default(OM2K_CON_GROUP_NODE);
+ install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_dec_cmd);
+ install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_conc_cmd);
install_element(BTS_NODE, &cfg_bts_is_conn_list_cmd);
+ install_element(BTS_NODE, &cfg_om2k_con_group_cmd);
return 0;
}