diff options
-rw-r--r-- | openbsc/include/openbsc/abis_om2000.h | 33 | ||||
-rw-r--r-- | openbsc/include/openbsc/vty.h | 1 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_om2000.c | 71 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_om2000_vty.c | 189 | ||||
-rw-r--r-- | openbsc/src/libcommon/common_vty.c | 10 |
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; { |