aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/abis_om2000.h33
-rw-r--r--openbsc/include/openbsc/vty.h1
-rw-r--r--openbsc/src/libbsc/abis_om2000.c71
-rw-r--r--openbsc/src/libbsc/abis_om2000_vty.c189
-rw-r--r--openbsc/src/libcommon/common_vty.c10
5 files changed, 235 insertions, 69 deletions
diff --git a/openbsc/include/openbsc/abis_om2000.h b/openbsc/include/openbsc/abis_om2000.h
index c745112f3..b093a0350 100644
--- a/openbsc/include/openbsc/abis_om2000.h
+++ b/openbsc/include/openbsc/abis_om2000.h
@@ -56,6 +56,39 @@ struct is_conn_group {
uint8_t ci;
};
+/* on-wire format for CON Path */
+struct om2k_con_path {
+ uint16_t ccp;
+ uint8_t ci;
+ uint8_t tag;
+ uint8_t tei;
+} __attribute__ ((packed));
+
+/* internal data format for CON group */
+struct con_group {
+ /* links list of CON groups in BTS */
+ struct llist_head list;
+ struct gsm_bts *bts;
+ /* CON Group ID */
+ uint8_t cg;
+ /* list of CON paths in this group */
+ struct llist_head paths;
+};
+
+/* internal data format for CON path */
+struct con_path {
+ /* links with con_group.paths */
+ struct llist_head list;
+ /* CON Connection Point */
+ uint16_t ccp;
+ /* Contiguity Index */
+ uint8_t ci;
+ /* Tag */
+ uint8_t tag;
+ /* TEI */
+ uint8_t tei;
+};
+
extern const struct abis_om2k_mo om2k_mo_cf;
extern const struct abis_om2k_mo om2k_mo_is;
extern const struct abis_om2k_mo om2k_mo_con;
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
index 315db0d11..ad2cd2a8a 100644
--- a/openbsc/include/openbsc/vty.h
+++ b/openbsc/include/openbsc/vty.h
@@ -29,6 +29,7 @@ enum bsc_vty_node {
NAT_BSC_NODE,
MSC_NODE,
OM2K_NODE,
+ OM2K_CON_GROUP_NODE,
TRUNK_NODE,
PGROUP_NODE,
MNCC_INT_NODE,
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;
}
diff --git a/openbsc/src/libcommon/common_vty.c b/openbsc/src/libcommon/common_vty.c
index a0674f0f1..834da516b 100644
--- a/openbsc/src/libcommon/common_vty.c
+++ b/openbsc/src/libcommon/common_vty.c
@@ -28,6 +28,7 @@
#include <openbsc/debug.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/bsc_nat.h>
+#include <openbsc/abis_om2000.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/command.h>
@@ -79,6 +80,15 @@ int bsc_vty_go_parent(struct vty *vty)
talloc_free(vty->index);
vty->index = NULL;
break;
+ case OM2K_CON_GROUP_NODE:
+ vty->node = BTS_NODE;
+ {
+ struct con_group *cg = vty->index;
+ struct gsm_bts *bts = cg->bts;
+ vty->index = bts;
+ vty->index_sub = &bts->description;
+ }
+ break;
case NAT_BSC_NODE:
vty->node = NAT_NODE;
{