aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libbsc
diff options
context:
space:
mode:
authorTobias Engel <tobias@ccc.de>2011-12-08 11:22:31 +0100
committerTobias Engel <tobias@ccc.de>2011-12-08 11:22:31 +0100
commit83d61285404f85e03212d09f471020c8ca7a7fd7 (patch)
tree502f13278f2dfe98de45c5daefe171e1dde6e448 /openbsc/src/libbsc
parent11e802aba933d2f32e6b46307af486b2928537fb (diff)
parent1c5dd2c9bbc26902cdad0487e090e97e983b0787 (diff)
Merge branch 'master' of git://git.osmocom.org/openbsc
Diffstat (limited to 'openbsc/src/libbsc')
-rw-r--r--openbsc/src/libbsc/Makefile.am1
-rw-r--r--openbsc/src/libbsc/abis_nm.c80
-rw-r--r--openbsc/src/libbsc/abis_om2000.c33
-rw-r--r--openbsc/src/libbsc/abis_rsl.c189
-rw-r--r--openbsc/src/libbsc/bsc_api.c58
-rw-r--r--openbsc/src/libbsc/bsc_init.c71
-rw-r--r--openbsc/src/libbsc/bsc_msc.c4
-rw-r--r--openbsc/src/libbsc/bsc_vty.c297
-rw-r--r--openbsc/src/libbsc/bts_ericsson_rbs2000.c41
-rw-r--r--openbsc/src/libbsc/bts_hsl_femtocell.c163
-rw-r--r--openbsc/src/libbsc/bts_init.c1
-rw-r--r--openbsc/src/libbsc/bts_ipaccess_nanobts.c200
-rw-r--r--openbsc/src/libbsc/bts_nokia_site.c1740
-rw-r--r--openbsc/src/libbsc/bts_siemens_bs11.c18
-rw-r--r--openbsc/src/libbsc/chan_alloc.c4
-rw-r--r--openbsc/src/libbsc/e1_config.c125
-rw-r--r--openbsc/src/libbsc/gsm_04_08_utils.c4
-rw-r--r--openbsc/src/libbsc/system_information.c4
18 files changed, 2643 insertions, 390 deletions
diff --git a/openbsc/src/libbsc/Makefile.am b/openbsc/src/libbsc/Makefile.am
index 3af4a2a3d..a8e05206c 100644
--- a/openbsc/src/libbsc/Makefile.am
+++ b/openbsc/src/libbsc/Makefile.am
@@ -11,6 +11,7 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
bts_ericsson_rbs2000.c \
bts_ipaccess_nanobts.c \
bts_siemens_bs11.c \
+ bts_nokia_site.c \
bts_hsl_femtocell.c \
bts_unknown.c \
chan_alloc.c \
diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c
index 49e86ba2c..a01826bd5 100644
--- a/openbsc/src/libbsc/abis_nm.c
+++ b/openbsc/src/libbsc/abis_nm.c
@@ -43,6 +43,7 @@
#include <openbsc/abis_nm.h>
#include <openbsc/misdn.h>
#include <openbsc/signal.h>
+#include <osmocom/abis/e1_input.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
@@ -113,15 +114,27 @@ static struct msgb *nm_msgb_alloc(void)
"OML");
}
+int _abis_nm_sendmsg(struct msgb *msg)
+{
+ msg->l2h = msg->data;
+
+ if (!msg->dst) {
+ LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ return abis_sendmsg(msg);
+}
+
/* Send a OML NM Message from BSC to BTS */
static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
{
- msg->trx = bts->c0;
+ msg->dst = bts->oml_link;
/* queue OML messages */
if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
- return _abis_nm_sendmsg(msg, 0);
+ return _abis_nm_sendmsg(msg);
} else {
msgb_enqueue(&bts->abis_queue, msg);
return 0;
@@ -186,7 +199,8 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct gsm_bts *bts = mb->trx->bts;
+ struct e1inp_sign_link *sign_link = mb->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
struct tlv_parsed tp;
struct gsm_nm_state *nm_state, new_state;
@@ -260,13 +274,14 @@ static int rx_fail_evt_rep(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
const uint8_t *p_val;
char *p_text;
LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
LOGPC(DNM, LOGL_ERROR, "Type=%s ",
@@ -391,6 +406,7 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
const uint8_t *sw_config;
int ret, sw_config_len, sw_descr_len;
@@ -401,13 +417,13 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
- ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
+ ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr, 0,
foh->data, oh->length-sizeof(*foh));
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
@@ -422,7 +438,7 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
if (sw_descr_len < 0)
return -EINVAL;
- return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
+ return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr,
@@ -434,26 +450,28 @@ static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
uint8_t adm_state;
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
return -EINVAL;
adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
- return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
+ return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
}
static int abis_nm_rx_lmt_event(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
DEBUGP(DNM, "LMT Event ");
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
@@ -474,7 +492,7 @@ static int abis_nm_rx_lmt_event(struct msgb *mb)
return 0;
}
-static void abis_nm_queue_send_next(struct gsm_bts *bts)
+void abis_nm_queue_send_next(struct gsm_bts *bts)
{
int wait = 0;
struct msgb *msg;
@@ -482,7 +500,7 @@ static void abis_nm_queue_send_next(struct gsm_bts *bts)
while (!llist_empty(&bts->abis_queue)) {
msg = msgb_dequeue(&bts->abis_queue);
wait = OBSC_NM_W_ACK_CB(msg);
- _abis_nm_sendmsg(msg, 0);
+ _abis_nm_sendmsg(msg);
if (wait)
break;
@@ -496,6 +514,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
uint8_t mt = foh->msg_type;
int ret = 0;
@@ -514,7 +533,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
DEBUGPC(DNM, "CAUSE=%s\n",
abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
@@ -524,7 +543,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
nack_data.msg = mb;
nack_data.mt = mt;
osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
return 0;
}
#if 0
@@ -565,13 +584,13 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
break;
case NM_MT_SET_BTS_ATTR_ACK:
/* The HSL wants an OPSTART _after_ the SI has been set */
- if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
- abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
+ if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
+ abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
}
break;
}
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
return ret;
}
@@ -580,12 +599,13 @@ static int abis_nm_rx_ipacc(struct msgb *mb);
static int abis_nm_rcvmsg_manuf(struct msgb *mb)
{
int rc;
- int bts_type = mb->trx->bts->type;
+ struct e1inp_sign_link *sign_link = mb->dst;
+ int bts_type = sign_link->trx->bts->type;
switch (bts_type) {
case GSM_BTS_TYPE_NANOBTS:
rc = abis_nm_rx_ipacc(mb);
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
default:
LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
@@ -1006,6 +1026,7 @@ static int sw_fill_window(struct abis_nm_sw *sw)
static int abis_nm_rcvmsg_sw(struct msgb *mb)
{
struct abis_om_fom_hdr *foh = msgb_l3(mb);
+ struct e1inp_sign_link *sign_link = mb->dst;
int rc = -1;
struct abis_nm_sw *sw = &g_sw;
enum sw_state old_state = sw->state;
@@ -1023,7 +1044,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cb_data, NULL);
rc = sw_fill_window(sw);
sw->state = SW_STATE_WAIT_SEGACK;
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
case NM_MT_LOAD_INIT_NACK:
if (sw->forced) {
@@ -1044,7 +1065,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cb_data, NULL);
sw->state = SW_STATE_ERROR;
}
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
}
break;
@@ -1065,7 +1086,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->state = SW_STATE_WAIT_ENDACK;
rc = sw_load_end(sw);
}
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
case NM_MT_LOAD_ABORT:
if (sw->cbfn)
@@ -1087,7 +1108,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
NM_MT_LOAD_END_ACK, mb,
sw->cb_data, NULL);
rc = 0;
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
case NM_MT_LOAD_END_NACK:
if (sw->forced) {
@@ -1107,7 +1128,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
NM_MT_LOAD_END_NACK, mb,
sw->cb_data, NULL);
}
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
}
case SW_STATE_WAIT_ACTACK:
@@ -1121,7 +1142,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cbfn(GSM_HOOK_NM_SWLOAD,
NM_MT_ACTIVATE_SW_ACK, mb,
sw->cb_data, NULL);
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
case NM_MT_ACTIVATE_SW_NACK:
DEBUGP(DNM, "Activate Software NACK\n");
@@ -1131,7 +1152,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cbfn(GSM_HOOK_NM_SWLOAD,
NM_MT_ACTIVATE_SW_NACK, mb,
sw->cb_data, NULL);
- abis_nm_queue_send_next(mb->trx->bts);
+ abis_nm_queue_send_next(sign_link->trx->bts);
break;
}
case SW_STATE_NONE:
@@ -2281,6 +2302,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
uint8_t idstrlen = oh->data[0];
struct tlv_parsed tp;
struct ipacc_ack_signal_data signal;
+ struct e1inp_sign_link *sign_link = msg->dst;
if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
@@ -2288,7 +2310,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
}
foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
- abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
+ abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_debugp_foh(DNM, foh);
@@ -2365,12 +2387,12 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
case NM_MT_IPACC_RSL_CONNECT_NACK:
case NM_MT_IPACC_SET_NVATTR_NACK:
case NM_MT_IPACC_GET_NVATTR_NACK:
- signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
+ signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
break;
case NM_MT_IPACC_SET_NVATTR_ACK:
- signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
+ signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
break;
diff --git a/openbsc/src/libbsc/abis_om2000.c b/openbsc/src/libbsc/abis_om2000.c
index b636e7375..e2e05780d 100644
--- a/openbsc/src/libbsc/abis_om2000.c
+++ b/openbsc/src/libbsc/abis_om2000.c
@@ -40,7 +40,7 @@
#include <openbsc/abis_nm.h>
#include <openbsc/abis_om2000.h>
#include <openbsc/signal.h>
-#include <openbsc/e1_input.h>
+#include <osmocom/abis/e1_input.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
@@ -800,6 +800,7 @@ static void signal_op_state(struct gsm_bts *bts, struct abis_om2k_mo *mo)
static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om2k_hdr *o2h;
+ struct gsm_bts_trx *trx;
int to_trx_oml;
msg->l2h = msg->data;
@@ -813,9 +814,8 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
case OM2K_MO_CLS_TX:
case OM2K_MO_CLS_RX:
/* Route through per-TRX OML Link to the appropriate TRX */
- to_trx_oml = 1;
- msg->trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
- if (!msg->trx) {
+ trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
+ if (!trx) {
LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
"non-existing TRX\n", om2k_mo_name(&o2h->mo));
return -ENODEV;
@@ -823,9 +823,8 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
break;
case OM2K_MO_CLS_TS:
/* Route through per-TRX OML Link to the appropriate TRX */
- to_trx_oml = 1;
- msg->trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so);
- if (!msg->trx) {
+ trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so);
+ if (!trx) {
LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
"non-existing TRX\n", om2k_mo_name(&o2h->mo));
return -ENODEV;
@@ -833,12 +832,12 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
break;
default:
/* Route through the IXU/DXU OML Link */
- msg->trx = bts->c0;
- to_trx_oml = 0;
+ trx = bts->c0;
break;
}
+ msg->dst = trx->oml_link;
- return _abis_nm_sendmsg(msg, to_trx_oml);
+ return _abis_nm_sendmsg(msg);
}
static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo,
@@ -1263,6 +1262,7 @@ 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 abis_om2k_hdr *o2h = msgb_l2(msg);
struct iwd_type iwd_types[16];
uint8_t num_iwd_types = o2h->data[2];
@@ -1316,29 +1316,31 @@ static int om2k_rx_negot_req(struct msgb *msg)
out_buf[0] = out_num_types;
- return abis_om2k_tx_negot_req_ack(msg->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
+ return abis_om2k_tx_negot_req_ack(sign_link->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
}
static int om2k_rx_start_res(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
int rc;
- rc = abis_om2k_tx_simple(msg->trx->bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
- rc = abis_om2k_tx_op_info(msg->trx->bts, &o2h->mo, 1);
+ rc = abis_om2k_tx_simple(sign_link->trx->bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
+ rc = abis_om2k_tx_op_info(sign_link->trx->bts, &o2h->mo, 1);
return rc;
}
static int om2k_rx_op_info_ack(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
/* This Acknowledgement does not contain the actual operational state,
* so we signal whatever state we saved when we sent the Op Info
* request */
- signal_op_state(msg->trx->bts, &o2h->mo);
+ signal_op_state(sign_link->trx->bts, &o2h->mo);
return 0;
}
@@ -1463,7 +1465,8 @@ static int process_mo_state(struct gsm_bts *bts, struct msgb *msg)
int abis_om2k_rcvmsg(struct msgb *msg)
{
- struct gsm_bts *bts = msg->trx->bts;
+ 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 abis_om_hdr *oh = &o2h->om;
uint16_t msg_type = ntohs(o2h->msg_type);
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 55db87227..b3920fa6d 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -38,8 +38,8 @@
#include <openbsc/signal.h>
#include <openbsc/meas_rep.h>
#include <openbsc/rtp_proxy.h>
+#include <osmocom/abis/e1_input.h>
#include <osmocom/gsm/rsl.h>
-
#include <osmocom/core/talloc.h>
#define RSL_ALLOC_SIZE 1024
@@ -178,6 +178,29 @@ static void print_rsl_cause(int lvl, const uint8_t *cause_v, uint8_t cause_len)
LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
}
+static void lchan_act_tmr_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+
+ LOGP(DRSL, LOGL_NOTICE, "%s Timeout during activation!\n",
+ gsm_lchan_name(lchan));
+
+ rsl_lchan_set_state(lchan, LCHAN_S_NONE);
+ lchan_free(lchan);
+}
+
+static void lchan_deact_tmr_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+
+ LOGP(DRSL, LOGL_NOTICE, "%s Timeout during deactivation!\n",
+ gsm_lchan_name(lchan));
+
+ rsl_lchan_set_state(lchan, LCHAN_S_NONE);
+ lchan_free(lchan);
+}
+
+
/* Send a BCCH_INFO message as per Chapter 8.5.1 */
int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type,
const uint8_t *data, int len)
@@ -192,7 +215,7 @@ int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
- msg->trx = trx;
+ msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -210,7 +233,7 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
- msg->trx = trx;
+ msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -229,7 +252,7 @@ int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -256,7 +279,7 @@ int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db)
msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -285,7 +308,7 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm)
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -384,7 +407,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, uint8_t chan_nr,
msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
- msg->trx = trx;
+ msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -427,7 +450,7 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
*/
msgb_v_put(msg, RSL_IE_CHAN_IDENT);
len = msgb_put(msg, 1);
- msgb_tlv_put(msg, GSM48_IE_CHANDESC_2, sizeof(cd), (const uint8_t *) &cd);
+ msgb_tv_fixed_put(msg, GSM48_IE_CHANDESC_2, sizeof(cd), (const uint8_t *) &cd);
if (lchan->ts->hopping.enabled)
msgb_tlv_put(msg, GSM48_IE_MA_AFTER, lchan->ts->hopping.ma_len,
@@ -463,7 +486,7 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
(uint8_t *) &lchan->mr_conf);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -502,7 +525,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
(uint8_t *) &lchan->mr_conf);
}
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -534,7 +557,7 @@ int rsl_encryption_cmd(struct msgb *msg)
init_dchan_hdr(dh, RSL_MT_ENCR_CMD);
dh->chan_nr = chan_nr;
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -550,7 +573,7 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
dh->chan_nr = gsm_lchan2chan_nr(lchan);
msg->lchan = lchan;
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan));
@@ -595,7 +618,7 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
dh->chan_nr = gsm_lchan2chan_nr(lchan);
msg->lchan = lchan;
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
@@ -605,13 +628,20 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
* be a problem when we have reassigned the channel to someone else and then can
* not figure out who used this channel.
*/
+ struct e1inp_sign_link *sign_link = msg->dst;
+
rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
lchan->error_timer.data = lchan;
lchan->error_timer.cb = error_timeout_cb;
osmo_timer_schedule(&lchan->error_timer,
- msg->trx->bts->network->T3111 + 2, 0);
+ sign_link->trx->bts->network->T3111 + 2, 0);
}
+ /* Start another timer or assume the BTS sends a ACK/NACK? */
+ lchan->act_timer.cb = lchan_deact_tmr_cb;
+ lchan->act_timer.data = lchan;
+ osmo_timer_schedule(&lchan->act_timer, 4, 0);
+
rc = abis_rsl_sendmsg(msg);
#ifdef ROLE_BSC
@@ -637,6 +667,8 @@ static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan)
DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan));
+ osmo_timer_del(&lchan->act_timer);
+
if (lchan->state != LCHAN_S_REL_REQ && lchan->state != LCHAN_S_REL_ERR)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
gsm_lchan_name(lchan),
@@ -664,7 +696,7 @@ int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len,
msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
- msg->trx = bts->c0;
+ msg->dst = bts->c0->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -708,7 +740,7 @@ int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val)
break;
}
- msg->trx = bts->c0;
+ msg->dst = bts->c0->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -728,7 +760,7 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n",
gsm_lchan_name(lchan), *(uint8_t *)mrpci);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -746,7 +778,7 @@ int rsl_data_request(struct msgb *msg, uint8_t link_id)
rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, gsm_lchan2chan_nr(msg->lchan),
link_id, 1);
- msg->trx = msg->lchan->ts->trx;
+ msg->dst = msg->lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -759,7 +791,7 @@ int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id)
msg = rsl_rll_simple(RSL_MT_EST_REQ, gsm_lchan2chan_nr(lchan),
link_id, 0);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -781,7 +813,7 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, uint8_t reason
/* FIXME: start some timer in case we don't receive a REL ACK ? */
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -802,6 +834,8 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
if (rslh->ie_chan != RSL_IE_CHAN_NR)
return -EINVAL;
+ osmo_timer_del(&msg->lchan->act_timer);
+
if (msg->lchan->state != LCHAN_S_ACT_REQ)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
gsm_lchan_name(msg->lchan),
@@ -826,7 +860,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
struct tlv_parsed tp;
- LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK",
+ osmo_timer_del(&msg->lchan->act_timer);
+
+ LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK ",
gsm_lchan_name(msg->lchan));
/* BTS has rejected channel activation ?!? */
@@ -840,6 +876,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
TLVP_LEN(&tp, RSL_IE_CAUSE));
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
+ else
+ rsl_rf_chan_release(msg->lchan, 1);
+
} else
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
@@ -972,9 +1011,11 @@ static int rsl_rx_meas_res(struct msgb *msg)
*TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET);
if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) {
+ struct e1inp_sign_link *sign_link = msg->dst;
+
val = TLVP_VAL(&tp, RSL_IE_L1_INFO);
mr->flags |= MEAS_REP_F_MS_L1;
- mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3);
+ mr->ms_l1.pwr = ms_pwr_dbm(sign_link->trx->bts->band, val[0] >> 3);
if (val[0] & 0x04)
mr->flags |= MEAS_REP_F_FPC;
mr->ms_l1.ta = val[1];
@@ -1019,8 +1060,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
int rc = 0;
char *ts_name;
+ struct e1inp_sign_link *sign_link = msg->dst;
- msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
+ msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
switch (rslh->c.msg_type) {
@@ -1087,8 +1129,9 @@ static int rsl_rx_error_rep(struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
struct tlv_parsed tp;
+ struct e1inp_sign_link *sign_link = msg->dst;
- LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(msg->trx));
+ LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(sign_link->trx));
rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh));
@@ -1104,6 +1147,7 @@ static int rsl_rx_error_rep(struct msgb *msg)
static int abis_rsl_rx_trx(struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
+ struct e1inp_sign_link *sign_link = msg->dst;
int rc = 0;
switch (rslh->msg_type) {
@@ -1112,16 +1156,22 @@ static int abis_rsl_rx_trx(struct msgb *msg)
break;
case RSL_MT_RF_RES_IND:
/* interference on idle channels of TRX */
- //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
+ //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(sign_link->trx));
break;
case RSL_MT_OVERLOAD:
/* indicate CCCH / ACCH / processor overload */
LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
- gsm_trx_name(msg->trx));
+ gsm_trx_name(sign_link->trx));
+ break;
+ case 0x42: /* Nokia specific: SI End ACK */
+ LOGP(DRSL, LOGL_INFO, "Nokia SI End ACK\n");
+ break;
+ case 0x43: /* Nokia specific: SI End NACK */
+ LOGP(DRSL, LOGL_INFO, "Nokia SI End NACK\n");
break;
default:
LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
- "type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type);
+ "type 0x%02x\n", gsm_trx_name(sign_link->trx), rslh->msg_type);
return -EINVAL;
}
return rc;
@@ -1187,7 +1237,8 @@ static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
/* MS has requested a channel on the RACH */
static int rsl_rx_chan_rqd(struct msgb *msg)
{
- struct gsm_bts *bts = msg->trx->bts;
+ struct e1inp_sign_link *sign_link = msg->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
struct gsm48_req_ref *rqd_ref;
enum gsm_chan_t lctype;
@@ -1262,7 +1313,11 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
lchan->tch_mode = GSM48_CMODE_SIGN;
- /* FIXME: Start another timer or assume the BTS sends a ACK/NACK? */
+ /* Start another timer or assume the BTS sends a ACK/NACK? */
+ lchan->act_timer.cb = lchan_act_tmr_cb;
+ lchan->act_timer.data = lchan;
+ osmo_timer_schedule(&lchan->act_timer, 4, 0);
+
rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0);
DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
@@ -1310,6 +1365,7 @@ static int rsl_send_imm_assignment(struct gsm_lchan *lchan)
/* MS has requested a channel on the RACH */
static int rsl_rx_ccch_load(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
uint16_t pg_buf_space;
uint16_t rach_slot_count = -1;
@@ -1319,11 +1375,11 @@ static int rsl_rx_ccch_load(struct msgb *msg)
switch (rslh->data[0]) {
case RSL_IE_PAGING_LOAD:
pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
- if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
+ if (is_ipaccess_bts(sign_link->trx->bts) && pg_buf_space == 0xffff) {
/* paging load below configured threshold, use 50 as default */
pg_buf_space = 50;
}
- paging_update_buffer_space(msg->trx->bts, pg_buf_space);
+ paging_update_buffer_space(sign_link->trx->bts, pg_buf_space);
break;
case RSL_IE_RACH_LOAD:
if (msg->data_len >= 7) {
@@ -1341,10 +1397,11 @@ static int rsl_rx_ccch_load(struct msgb *msg)
static int abis_rsl_rx_cchan(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
int rc = 0;
- msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
+ msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr);
switch (rslh->c.msg_type) {
case RSL_MT_CHAN_RQD:
@@ -1424,12 +1481,13 @@ static void rsl_handle_release(struct gsm_lchan *lchan)
static int abis_rsl_rx_rll(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
int rc = 0;
char *ts_name;
uint8_t sapi = rllh->link_id & 7;
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
+ msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi);
@@ -1533,10 +1591,6 @@ static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
{
struct gsm_network *net = lchan->ts->trx->bts->network;
- /* allow to hardcode the rtp payload */
- if (net->hardcoded_rtp_payload != 0)
- return net->hardcoded_rtp_payload;
-
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_V1:
switch (lchan->type) {
@@ -1558,9 +1612,8 @@ static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
case GSM48_CMODE_SPEECH_AMR:
switch (lchan->type) {
case GSM_LCHAN_TCH_F:
- return RTP_PT_AMR_FULL;
case GSM_LCHAN_TCH_H:
- return RTP_PT_AMR_HALF;
+ return RTP_PT_AMR;
default:
break;
}
@@ -1647,7 +1700,7 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan)
gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
lchan->abis_ip.rtp_payload);
- msg->trx = lchan->ts->trx;
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -1689,8 +1742,8 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, uint32_t ip, uint16_t port,
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
if (rtp_payload2)
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
-
- msg->trx = lchan->ts->trx;
+
+ msg->dst = lchan->ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -1728,7 +1781,7 @@ int rsl_ipacc_pdch_activate(struct gsm_bts_trx_ts *ts, int act)
DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_ts_name(ts),
act ? "" : "DE");
- msg->trx = ts->trx;
+ msg->dst = ts->trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
@@ -1793,11 +1846,12 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg)
static int abis_rsl_rx_ipacc(struct msgb *msg)
{
+ struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
char *ts_name;
int rc = 0;
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
+ msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
switch (rllh->c.msg_type) {
@@ -1903,3 +1957,50 @@ int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
return abis_rsl_sendmsg(cb_cmd);
}
+
+int rsl_nokia_si_begin(struct gsm_bts_trx *trx)
+{
+ struct abis_rsl_common_hdr *ch;
+ struct msgb *msg = rsl_msgb_alloc();
+
+ ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
+ ch->msg_discr = ABIS_RSL_MDISC_TRX;
+ ch->msg_type = 0x40; /* Nokia SI Begin */
+
+ msg->dst = trx->rsl_link;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+int rsl_nokia_si_end(struct gsm_bts_trx *trx)
+{
+ struct abis_rsl_common_hdr *ch;
+ struct msgb *msg = rsl_msgb_alloc();
+
+ ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
+ ch->msg_discr = ABIS_RSL_MDISC_TRX;
+ ch->msg_type = 0x41; /* Nokia SI End */
+
+ msgb_tv_put(msg, 0xFD, 0x00); /* Nokia Pagemode Info, No paging reorganisation required */
+
+ msg->dst = trx->rsl_link;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction)
+{
+ struct abis_rsl_common_hdr *ch;
+ struct msgb *msg = rsl_msgb_alloc();
+
+ ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
+ ch->msg_discr = ABIS_RSL_MDISC_DED_CHAN;
+ ch->msg_type = RSL_MT_BS_POWER_CONTROL;
+
+ msgb_tv_put(msg, RSL_IE_CHAN_NR, channel);
+ msgb_tv_put(msg, RSL_IE_BS_POWER, reduction); /* reduction in 2dB steps */
+
+ msg->dst = trx->rsl_link;
+
+ return abis_rsl_sendmsg(msg);
+}
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index 70d641396..c1aedb2fb 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -1,7 +1,7 @@
/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
-/* (C) 2010 by Holger Hans Peter Freyther
- * (C) 2010 by On-Waves
+/* (C) 2010-2011 by Holger Hans Peter Freyther
+ * (C) 2010-2011 by On-Waves
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
@@ -136,8 +136,12 @@ static void assignment_t10_timeout(void *_conn)
LOGP(DMSC, LOGL_ERROR, "Assigment T10 timeout on %p\n", conn);
- /* normal release on the secondary channel */
- lchan_release(conn->secondary_lchan, 0, 1);
+ /*
+ * normal release on the secondary channel but only if the
+ * secondary_channel has not been released by the handle_chan_nack.
+ */
+ if (conn->secondary_lchan)
+ lchan_release(conn->secondary_lchan, 0, 1);
conn->secondary_lchan = NULL;
/* inform them about the failure */
@@ -145,6 +149,17 @@ static void assignment_t10_timeout(void *_conn)
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
}
+/**
+ * Handle the multirate config
+ */
+static void handle_mr_config(struct gsm_subscriber_connection *conn,
+ struct gsm_lchan *lchan)
+{
+ lchan->mr_conf.ver = 1;
+ lchan->mr_conf.icmi = 1;
+ lchan->mr_conf.m5_90 = 1;
+}
+
/*
* Start a new assignment and make sure that it is completed within T10 either
* positively, negatively or by the timeout.
@@ -184,11 +199,8 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
new_lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
/* handle AMR correctly */
- if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
- new_lchan->mr_conf.ver = 1;
- new_lchan->mr_conf.icmi = 1;
- new_lchan->mr_conf.m5_90 = 1;
- }
+ if (chan_mode == GSM48_CMODE_SPEECH_AMR)
+ handle_mr_config(conn, new_lchan);
if (rsl_chan_activate_lchan(new_lchan, 0x1, 0, 0) < 0) {
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
@@ -258,6 +270,7 @@ int bsc_api_init(struct gsm_network *network, struct bsc_api *api)
return 0;
}
+/*! \brief process incoming 08.08 DTAP from MSC (send via BTS to MS) */
int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg, int link_id, int allow_sach)
{
@@ -273,7 +286,7 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
sapi = link_id & 0x7;
msg->lchan = conn->lchan;
- msg->trx = msg->lchan->ts->trx;
+ msg->dst = msg->lchan->ts->trx->rsl_link;
/* If we are on a TCH and need to submit a SMS (on SAPI=3) we need to use the SACH */
if (allow_sach && sapi != 0) {
@@ -282,7 +295,9 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
}
msg->l3h = msg->data;
+ /* is requested SAPI already up? */
if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) {
+ /* Establish L2 for additional SAPI */
OBSC_LINKID_CB(msg) = link_id;
if (rll_establish(msg->lchan, sapi, rll_ind_cb, msg) != 0) {
msgb_free(msg);
@@ -291,6 +306,7 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
}
return 0;
} else {
+ /* Directly forward via RLL/RSL to BTS */
return rsl_data_request(msg, link_id);
}
}
@@ -299,8 +315,8 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
* Send a GSM08.08 Assignment Request. Right now this does not contain the
* audio codec type or the allowed rates for the config. It is assumed that
* this is for audio handling and that when we have a TCH it is capable of
- * handling the audio codec. On top of that it is assumed that we are using
- * AMR 5.9 when assigning a TCH/H.
+ * handling the audio codec. In case AMR is used we will leave the multi
+ * rate configuration to someone else.
*/
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
{
@@ -313,11 +329,8 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in
} else {
LOGP(DMSC, LOGL_NOTICE,
"Sending ChanModify for speech %d %d\n", chan_mode, full_rate);
- if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
- conn->lchan->mr_conf.ver = 1;
- conn->lchan->mr_conf.icmi = 1;
- conn->lchan->mr_conf.m5_90 = 1;
- }
+ if (chan_mode == GSM48_CMODE_SPEECH_AMR)
+ handle_mr_config(conn, conn->lchan);
gsm48_lchan_modify(conn->lchan, chan_mode);
}
@@ -367,7 +380,8 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(conn->lchan);
- api->assign_compl(conn, gh->data[0],
+ if (api->assign_compl)
+ api->assign_compl(conn, gh->data[0],
lchan_to_chosen_channel(conn->lchan),
conn->lchan->encr.alg_id,
chan_mode_to_speech(conn->lchan));
@@ -459,6 +473,7 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
api->dtap(conn, link_id, msg);
}
+/*! \brief RSL has received a DATA INDICATION with L3 from MS */
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
{
int rc;
@@ -474,8 +489,11 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
if (lchan->conn) {
+ /* if we already have a connection, forward via DTAP to
+ * MSC */
dispatch_dtap(lchan->conn, link_id, msg);
} else {
+ /* allocate a new connection */
rc = BSC_API_CONN_POL_REJECT;
lchan->conn = subscr_con_allocate(msg->lchan);
if (!lchan->conn) {
@@ -483,6 +501,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
return -1;
}
+ /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */
rc = api->compl_l3(lchan->conn, msg, 0);
if (rc != BSC_API_CONN_POL_ACCEPT) {
@@ -495,6 +514,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
return 0;
}
+/*! \brief We received a GSM 08.08 CIPHER MODE from the MSC */
int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
const uint8_t *key, int len, int include_imeisv)
{
@@ -655,7 +675,7 @@ static void handle_chan_ack(struct gsm_subscriber_connection *conn,
return;
LOGP(DMSC, LOGL_NOTICE, "Sending assignment on chan: %p\n", lchan);
- gsm48_send_rr_ass_cmd(conn->lchan, lchan, 0x3);
+ gsm48_send_rr_ass_cmd(conn->lchan, lchan, lchan->ms_power);
}
static void handle_chan_nack(struct gsm_subscriber_connection *conn,
diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c
index 02a3adfcc..529ffc040 100644
--- a/openbsc/src/libbsc/bsc_init.c
+++ b/openbsc/src/libbsc/bsc_init.c
@@ -33,6 +33,8 @@
#include <openbsc/chan_alloc.h>
#include <osmocom/core/talloc.h>
#include <openbsc/ipaccess.h>
+#include <osmocom/gsm/sysinfo.h>
+#include <openbsc/e1_config.h>
/* global pointer to the gsm network data structure */
extern struct gsm_network *bsc_gsmnet;
@@ -45,16 +47,21 @@ static int oml_msg_nack(struct nm_nack_signal_data *nack)
if (nack->mt == NM_MT_SET_BTS_ATTR_NACK) {
- LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. "
+ LOGP(DNM, LOGL_ERROR, "Failed to set BTS attributes. That is fatal. "
"Was the bts type and frequency properly specified?\n");
- exit(-1);
+ goto drop_bts;
} else {
LOGP(DNM, LOGL_ERROR, "Got a NACK going to drop the OML links.\n");
- for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
- struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
- if (is_ipaccess_bts(bts))
- ipaccess_drop_oml(bts);
- }
+ goto drop_bts;
+ }
+
+ return 0;
+
+drop_bts:
+ for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
+ struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
+ if (is_ipaccess_bts(bts))
+ ipaccess_drop_oml(bts);
}
return 0;
@@ -82,7 +89,7 @@ int bsc_shutdown_net(struct gsm_network *net)
llist_for_each_entry(bts, &net->bts_list, list) {
LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr);
- osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
+ osmo_signal_dispatch(SS_L_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
}
return 0;
@@ -249,8 +256,19 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
bsc_gsmnet->network_code, trx->bts->location_area_code,
trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc);
+
+ if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
+ rsl_nokia_si_begin(trx);
+ }
+
set_system_infos(trx);
+ if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
+ /* channel unspecific, power reduction in 2 dB steps */
+ rsl_bs_power_control(trx, 0xFF, trx->max_power_red / 2);
+ rsl_nokia_si_end(trx);
+ }
+
for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
generate_ma_for_ts(&trx->ts[i]);
}
@@ -263,16 +281,34 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
struct gsm_bts_trx *trx = isd->trx;
int ts_no, lchan_no;
- if (subsys != SS_INPUT)
+ if (subsys != SS_L_INPUT)
return -EINVAL;
switch (signal) {
- case S_INP_TEI_UP:
+ case S_L_INP_TEI_UP:
+ if (isd->link_type == E1INP_SIGN_OML) {
+ /* TODO: this is required for the Nokia BTS, hopping is configured
+ during OML, other MA is not set. */
+ struct gsm_bts_trx *cur_trx;
+ /* was static in system_information.c */
+ extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
+ uint8_t ca[20];
+ /* has to be called before generate_ma_for_ts to
+ set bts->si_common.cell_alloc */
+ generate_cell_chan_list(ca, trx->bts);
+
+ llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++)
+ generate_ma_for_ts(&cur_trx->ts[i]);
+ }
+ }
if (isd->link_type == E1INP_SIGN_RSL)
bootstrap_rsl(trx);
break;
- case S_INP_TEI_DN:
- LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
+ case S_L_INP_TEI_DN:
+ LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
if (isd->link_type == E1INP_SIGN_OML)
osmo_counter_inc(trx->bts->network->stats.bts.oml_fail);
@@ -440,7 +476,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
return rc;
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
- osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
+ osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
rc = bootstrap_bts(bts);
@@ -448,14 +484,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n");
return rc;
}
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_HSL_FEMTO:
- break;
- default:
- rc = e1_reconfig_bts(bts);
- break;
- }
+ rc = e1_reconfig_bts(bts);
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n");
return rc;
diff --git a/openbsc/src/libbsc/bsc_msc.c b/openbsc/src/libbsc/bsc_msc.c
index e9ffce39a..66288a316 100644
--- a/openbsc/src/libbsc/bsc_msc.c
+++ b/openbsc/src/libbsc/bsc_msc.c
@@ -21,11 +21,13 @@
#include <openbsc/bsc_msc.h>
#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
+#include <osmocom/abis/ipaccess.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/tlv.h>
+
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 54d7c6e35..ed74397ec 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -30,7 +30,7 @@
#include <osmocom/core/linuxlist.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
+#include <osmocom/abis/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_om2000.h>
#include <osmocom/core/utils.h>
@@ -52,6 +52,14 @@
#include "../../bscconfig.h"
+
+#define NETWORK_STR "Configure the GSM network\n"
+#define CODE_CMD_STR "Code commands\n"
+#define NAME_CMD_STR "Name Commands\n"
+#define NAME_STR "Name to use\n"
+#define LCHAN_NR_STR "Logical Channel Number\n"
+
+
/* FIXME: this should go to some common file */
static const struct value_string gprs_ns_timer_strs[] = {
{ 0, "tns-block" },
@@ -255,6 +263,9 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
bts->oml_tei, VTY_NEWLINE);
else if (bts->type == GSM_BTS_TYPE_HSL_FEMTO)
vty_out(vty, " Serial Number: %lu%s", bts->hsl.serno, VTY_NEWLINE);
+ else if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
+ vty_out(vty, " Skip Reset: %d%s",
+ bts->nokia.skip_reset, VTY_NEWLINE);
vty_out(vty, " NM State: ");
net_dump_nmstate(vty, &bts->mo.nm_state);
vty_out(vty, " Site Mgr NM State: ");
@@ -437,6 +448,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+ if (bts->tz_bts_specific != 0)
+ vty_out(vty, " timezone %d %d%s", bts->tzhr, bts->tzmn, VTY_NEWLINE);
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, " cell reselection hysteresis %u%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@@ -498,7 +511,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
get_value_string(osmo_sitype_strs, i), VTY_NEWLINE);
vty_out(vty, " system-information %s static %s%s",
get_value_string(osmo_sitype_strs, i),
- osmo_osmo_hexdump_nospc(bts->si_buf[i], sizeof(bts->si_buf[i])),
+ osmo_hexdump_nospc(bts->si_buf[i], sizeof(bts->si_buf[i])),
VTY_NEWLINE);
}
}
@@ -506,10 +519,16 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
case GSM_BTS_TYPE_NANOBTS:
vty_out(vty, " ip.access unit_id %u %u%s",
bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
- vty_out(vty, " oml ip.access stream_id %u%s", bts->oml_tei, VTY_NEWLINE);
+ vty_out(vty, " oml ip.access stream_id %u line %u%s",
+ bts->oml_tei, bts->oml_e1_link.e1_nr, VTY_NEWLINE);
break;
case GSM_BTS_TYPE_HSL_FEMTO:
vty_out(vty, " hsl serial-number %lu%s", bts->hsl.serno, VTY_NEWLINE);
+ vty_out(vty, " oml hsl line %u%s",
+ bts->oml_e1_link.e1_nr, VTY_NEWLINE);
+ break;
+ case GSM_BTS_TYPE_NOKIA_SITE:
+ vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE);
break;
default:
config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
@@ -942,7 +961,7 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
lchan_nr++) {
lchan = &ts->lchan[lchan_nr];
- if (lchan->type == GSM_LCHAN_NONE)
+ if ((lchan->type == GSM_LCHAN_NONE) && (lchan->state == LCHAN_S_NONE))
continue;
dump_cb(vty, lchan);
}
@@ -959,7 +978,7 @@ DEFUN(show_lchan,
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n"
"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- "Logical Channel Number\n")
+ LCHAN_NR_STR)
{
return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
@@ -969,125 +988,13 @@ DEFUN(show_lchan_summary,
show_lchan_summary_cmd,
"show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n"
+ "Short summary\n"
"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- "Logical Channel Number\n")
+ LCHAN_NR_STR)
{
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
-static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
-{
- vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
-}
-
-DEFUN(show_e1drv,
- show_e1drv_cmd,
- "show e1_driver",
- SHOW_STR "Display information about available E1 drivers\n")
-{
- struct e1inp_driver *drv;
-
- llist_for_each_entry(drv, &e1inp_driver_list, list)
- e1drv_dump_vty(vty, drv);
-
- return CMD_SUCCESS;
-}
-
-static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line)
-{
- vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
- line->num, line->name ? line->name : "",
- line->driver->name, VTY_NEWLINE);
-}
-
-DEFUN(show_e1line,
- show_e1line_cmd,
- "show e1_line [line_nr]",
- SHOW_STR "Display information about a E1 line\n"
- "E1 Line Number\n")
-{
- struct e1inp_line *line;
-
- if (argc >= 1) {
- int num = atoi(argv[0]);
- llist_for_each_entry(line, &e1inp_line_list, list) {
- if (line->num == num) {
- e1line_dump_vty(vty, line);
- return CMD_SUCCESS;
- }
- }
- return CMD_WARNING;
- }
-
- llist_for_each_entry(line, &e1inp_line_list, list)
- e1line_dump_vty(vty, line);
-
- return CMD_SUCCESS;
-}
-
-static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
-{
- if (ts->type == E1INP_TS_TYPE_NONE)
- return;
- vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
- ts->num, ts->line->num, e1inp_tstype_name(ts->type),
- VTY_NEWLINE);
-}
-
-DEFUN(show_e1ts,
- show_e1ts_cmd,
- "show e1_timeslot [line_nr] [ts_nr]",
- SHOW_STR "Display information about a E1 timeslot\n"
- "E1 Line Number\n" "E1 Timeslot Number\n")
-{
- struct e1inp_line *line = NULL;
- struct e1inp_ts *ts;
- int ts_nr;
-
- if (argc == 0) {
- llist_for_each_entry(line, &e1inp_line_list, list) {
- for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- }
- }
- return CMD_SUCCESS;
- }
- if (argc >= 1) {
- int num = atoi(argv[0]);
- struct e1inp_line *l;
- llist_for_each_entry(l, &e1inp_line_list, list) {
- if (l->num == num) {
- line = l;
- break;
- }
- }
- if (!line) {
- vty_out(vty, "E1 line %s is invalid%s",
- argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- if (argc >= 2) {
- ts_nr = atoi(argv[1]);
- if (ts_nr >= NUM_E1_TS) {
- vty_out(vty, "E1 timeslot %s is invalid%s",
- argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- return CMD_SUCCESS;
- } else {
- for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- }
- return CMD_SUCCESS;
- }
- return CMD_SUCCESS;
-}
-
static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
{
vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
@@ -1133,8 +1040,6 @@ DEFUN(show_paging,
return CMD_SUCCESS;
}
-#define NETWORK_STR "Configure the GSM network\n"
-
DEFUN(cfg_net,
cfg_net_cmd,
"network", NETWORK_STR)
@@ -1145,11 +1050,13 @@ DEFUN(cfg_net,
return CMD_SUCCESS;
}
-
DEFUN(cfg_net_ncc,
cfg_net_ncc_cmd,
"network country code <1-999>",
- "Set the GSM network country code")
+ "Set the GSM network country code\n"
+ "Country commands\n"
+ CODE_CMD_STR
+ "Network Country Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1160,8 +1067,11 @@ DEFUN(cfg_net_ncc,
DEFUN(cfg_net_mnc,
cfg_net_mnc_cmd,
- "mobile network code <1-999>",
- "Set the GSM mobile network code")
+ "mobile network code <0-999>",
+ "Set the GSM mobile network code\n"
+ "Network Commands\n"
+ CODE_CMD_STR
+ "Mobile Network Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1173,7 +1083,7 @@ DEFUN(cfg_net_mnc,
DEFUN(cfg_net_name_short,
cfg_net_name_short_cmd,
"short name NAME",
- "Set the short GSM network name")
+ "Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1184,7 +1094,7 @@ DEFUN(cfg_net_name_short,
DEFUN(cfg_net_name_long,
cfg_net_name_long_cmd,
"long name NAME",
- "Set the long GSM network name")
+ "Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1301,11 +1211,13 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd,
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
+#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
"handover window rxlev averaging <1-10>",
HO_WIN_RXLEV_STR
- "How many RxLev measurements are used for averaging")
+ "How many RxLev measurements are used for averaging\n"
+ HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
@@ -1315,7 +1227,8 @@ DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
"handover window rxqual averaging <1-10>",
HO_WIN_RXQUAL_STR
- "How many RxQual measurements are used for averaging")
+ "How many RxQual measurements are used for averaging\n"
+ HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
@@ -1324,8 +1237,9 @@ DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
"handover window rxlev neighbor averaging <1-10>",
- HO_WIN_RXLEV_STR
- "How many RxQual measurements are used for averaging")
+ HO_WIN_RXLEV_STR "Neighbor\n"
+ "How many RxQual measurements are used for averaging\n"
+ HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
@@ -1335,7 +1249,8 @@ DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
"handover power budget interval <1-99>",
HO_PBUDGET_STR
- "How often to check if we have a better cell (SACCH frames)")
+ "How often to check if we have a better cell (SACCH frames)\n"
+ "Interval\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_interval = atoi(argv[0]);
@@ -1345,7 +1260,8 @@ DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
"handover power budget hysteresis <0-999>",
HO_PBUDGET_STR
- "How many dB does a neighbor to be stronger to become a HO candidate")
+ "How many dB does a neighbor to be stronger to become a HO candidate\n"
+ "Hysteresis\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
@@ -1355,7 +1271,8 @@ DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
"handover maximum distance <0-9999>",
HANDOVER_STR
- "How big is the maximum timing advance before HO is forced")
+ "How big is the maximum timing advance before HO is forced\n"
+ "Distance\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.max_distance = atoi(argv[0]);
@@ -1365,7 +1282,10 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
DEFUN(cfg_net_pag_any_tch,
cfg_net_pag_any_tch_cmd,
"paging any use tch (0|1)",
- "Assign a TCH when receiving a Paging Any request")
+ "Assign a TCH when receiving a Paging Any request\n"
+ "Any Channel\n" "Use\n" "TCH\n"
+ "Do not use TCH for Paging Request Any\n"
+ "Do use TCH for Paging Request Any\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->pag_any_tch = atoi(argv[0]);
@@ -1378,7 +1298,7 @@ DEFUN(cfg_net_pag_any_tch,
cfg_net_T##number##_cmd, \
"timer t" #number " <0-65535>", \
"Configure GSM Timers\n" \
- doc) \
+ doc "Timer Value\n") \
{ \
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
int value = atoi(argv[0]); \
@@ -1393,24 +1313,24 @@ DEFUN(cfg_net_pag_any_tch,
return CMD_SUCCESS; \
}
-DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.")
-DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
-DECLARE_TIMER(3105, "Currently not used.")
-DECLARE_TIMER(3107, "Currently not used.")
-DECLARE_TIMER(3109, "Currently not used.")
-DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
-DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
-DECLARE_TIMER(3115, "Currently not used.")
-DECLARE_TIMER(3117, "Currently not used.")
-DECLARE_TIMER(3119, "Currently not used.")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
-DECLARE_TIMER(3141, "Currently not used.")
+DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
+DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
+DECLARE_TIMER(3105, "Currently not used.\n")
+DECLARE_TIMER(3107, "Currently not used.\n")
+DECLARE_TIMER(3109, "Currently not used.\n")
+DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
+DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
+DECLARE_TIMER(3115, "Currently not used.\n")
+DECLARE_TIMER(3117, "Currently not used.\n")
+DECLARE_TIMER(3119, "Currently not used.\n")
+DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
+DECLARE_TIMER(3141, "Currently not used.\n")
DEFUN(cfg_net_dtx,
cfg_net_dtx_cmd,
"dtx-used (0|1)",
"Enable the usage of DTX.\n"
- "DTX is enabled/disabled")
+ "DTX is disabled\n" "DTX is enabled\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->dtx_enabled = atoi(argv[0]);
@@ -1466,7 +1386,7 @@ DEFUN(cfg_bts,
DEFUN(cfg_bts_type,
cfg_bts_type_cmd,
"type TYPE",
- "Set the BTS type\n")
+ "Set the BTS type\n" "Type\n")
{
struct gsm_bts *bts = vty->index;
int rc;
@@ -1481,7 +1401,7 @@ DEFUN(cfg_bts_type,
DEFUN(cfg_bts_band,
cfg_bts_band_cmd,
"band BAND",
- "Set the frequency band of this BTS\n")
+ "Set the frequency band of this BTS\n" "Frequency band\n")
{
struct gsm_bts *bts = vty->index;
int band = gsm_band_parse(argv[0]);
@@ -1577,6 +1497,31 @@ DEFUN(cfg_bts_bsic,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_timezone,
+ cfg_bts_timezone_cmd,
+ "timezone <-19-19> (0|15|30|45)",
+ "Set the Timezone Offset of this BTS\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int tzhr = atoi(argv[0]);
+ int tzmn = atoi(argv[1]);
+
+ bts->tzhr = tzhr;
+ bts->tzmn = tzmn;
+ bts->tz_bts_specific=1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_timezone,
+ cfg_bts_no_timezone_cmd,
+ "no timezone",
+ "disable bts specific timezone\n")
+{
+ struct gsm_bts *bts = vty->index;
+ bts->tz_bts_specific=0;
+ return CMD_SUCCESS;
+}
DEFUN(cfg_bts_unit_id,
cfg_bts_unit_id_cmd,
@@ -1615,17 +1560,34 @@ DEFUN(cfg_bts_serno,
return CMD_SUCCESS;
}
+DEFUN(cfg_bts_nokia_site_skip_reset,
+ cfg_bts_nokia_site_skip_reset_cmd,
+ "nokia_site skip-reset (0|1)",
+ "Skip the reset step during bootstrap process of this BTS\n")
+{
+ struct gsm_bts *bts = vty->index;
+
+ if (bts->type != GSM_BTS_TYPE_NOKIA_SITE) {
+ vty_out(vty, "%% BTS is not of Nokia *Site type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->nokia.skip_reset = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
#define OML_STR "Organization & Maintenance Link\n"
#define IPA_STR "ip.access Specific Options\n"
DEFUN(cfg_bts_stream_id,
cfg_bts_stream_id_cmd,
- "oml ip.access stream_id <0-255>",
+ "oml ip.access stream_id <0-255> line E1_LINE",
OML_STR IPA_STR
"Set the ip.access Stream ID of the OML link of this BTS\n")
{
struct gsm_bts *bts = vty->index;
- int stream_id = atoi(argv[0]);
+ int stream_id = atoi(argv[0]), linenr = atoi(argv[1]);
if (!is_ipaccess_bts(bts)) {
vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
@@ -1633,6 +1595,27 @@ DEFUN(cfg_bts_stream_id,
}
bts->oml_tei = stream_id;
+ /* This is used by e1inp_bind_ops callback for each BTS model. */
+ bts->oml_e1_link.e1_nr = linenr;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_hsl_oml,
+ cfg_bts_hsl_oml_cmd,
+ "oml hsl line E1_LINE",
+ OML_STR "HSL femto Specific Options"
+ "Set OML link of this HSL femto BTS\n")
+{
+ struct gsm_bts *bts = vty->index;
+ int linenr = atoi(argv[0]);
+
+ if (!(bts->type == GSM_BTS_TYPE_HSL_FEMTO)) {
+ vty_out(vty, "%% BTS is not of HSL type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ bts->oml_e1_link.e1_nr = linenr;
return CMD_SUCCESS;
}
@@ -2678,10 +2661,6 @@ int bsc_vty_init(const struct log_info *cat)
install_element_ve(&show_lchan_summary_cmd);
install_element_ve(&logging_fltr_imsi_cmd);
- install_element_ve(&show_e1drv_cmd);
- install_element_ve(&show_e1line_cmd);
- install_element_ve(&show_e1ts_cmd);
-
install_element_ve(&show_paging_cmd);
logging_vty_add_cmds(cat);
@@ -2739,8 +2718,12 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_tsc_cmd);
install_element(BTS_NODE, &cfg_bts_bsic_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
+ install_element(BTS_NODE, &cfg_bts_timezone_cmd);
+ install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_serno_cmd);
+ install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
install_element(BTS_NODE, &cfg_bts_stream_id_cmd);
+ install_element(BTS_NODE, &cfg_bts_hsl_oml_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_cmd);
diff --git a/openbsc/src/libbsc/bts_ericsson_rbs2000.c b/openbsc/src/libbsc/bts_ericsson_rbs2000.c
index 9c98a9fef..d603033e5 100644
--- a/openbsc/src/libbsc/bts_ericsson_rbs2000.c
+++ b/openbsc/src/libbsc/bts_ericsson_rbs2000.c
@@ -26,10 +26,10 @@
#include <openbsc/gsm_data.h>
#include <openbsc/abis_om2000.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/e1_input.h>
+#include <osmocom/abis/e1_input.h>
#include <openbsc/signal.h>
-#include "../libabis/input/lapd.h"
+#include <osmocom/abis/lapd.h>
static void bootstrap_om_bts(struct gsm_bts *bts)
{
@@ -70,9 +70,9 @@ static void start_sabm_in_line(struct e1inp_line *line, int start)
llist_for_each_entry(link, &ts->sign.sign_links, list) {
if (start)
- lapd_sap_start(ts->driver.dahdi.lapd, link->tei, link->sapi);
+ lapd_sap_start(ts->lapd, link->tei, link->sapi);
else
- lapd_sap_stop(ts->driver.dahdi.lapd, link->tei, link->sapi);
+ lapd_sap_stop(ts->lapd, link->tei, link->sapi);
}
}
}
@@ -83,7 +83,7 @@ static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
{
struct gsm_bts *bts;
- if (subsys != SS_GLOBAL)
+ if (subsys != SS_L_GLOBAL)
return 0;
switch (signal) {
@@ -103,11 +103,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
- if (subsys != SS_INPUT)
+ if (subsys != SS_L_INPUT)
return 0;
switch (signal) {
- case S_INP_TEI_UP:
+ case S_L_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type != GSM_BTS_TYPE_RBS2000)
@@ -119,22 +119,19 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
break;
}
break;
- case S_INP_LINE_INIT:
- /* Right now Ericsson RBS are only supported on DAHDI */
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
+ case S_L_INP_LINE_INIT:
+ case S_L_INP_LINE_NOALARM:
+ if (strcasecmp(isd->line->driver->name, "DAHDI")
+ && strcasecmp(isd->line->driver->name, "MISDN_LAPD"))
break;
start_sabm_in_line(isd->line, 1);
break;
- case S_INP_LINE_ALARM:
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
+ case S_L_INP_LINE_ALARM:
+ if (strcasecmp(isd->line->driver->name, "DAHDI")
+ && strcasecmp(isd->line->driver->name, "MISDN_LAPD"))
break;
start_sabm_in_line(isd->line, 0);
break;
- case S_INP_LINE_NOALARM:
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
- break;
- start_sabm_in_line(isd->line, 1);
- break;
}
return 0;
@@ -244,12 +241,18 @@ static void config_write_bts(struct vty *vty, struct gsm_bts *bts)
static int bts_model_rbs2k_start(struct gsm_network *net);
+static void bts_model_rbs2k_e1line_bind_ops(struct e1inp_line *line)
+{
+ e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
+}
+
static struct gsm_bts_model model_rbs2k = {
.type = GSM_BTS_TYPE_RBS2000,
.name = "rbs2000",
.start = bts_model_rbs2k_start,
.oml_rcvmsg = &abis_om2k_rcvmsg,
.config_write_bts = &config_write_bts,
+ .e1line_bind_ops = &bts_model_rbs2k_e1line_bind_ops,
};
static int bts_model_rbs2k_start(struct gsm_network *net)
@@ -260,8 +263,8 @@ static int bts_model_rbs2k_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HOPPING);
gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HSCSD);
- osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
- osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
+ 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;
diff --git a/openbsc/src/libbsc/bts_hsl_femtocell.c b/openbsc/src/libbsc/bts_hsl_femtocell.c
index f94369356..ebab34aeb 100644
--- a/openbsc/src/libbsc/bts_hsl_femtocell.c
+++ b/openbsc/src/libbsc/bts_hsl_femtocell.c
@@ -28,13 +28,18 @@
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/signal.h>
-#include <openbsc/e1_input.h>
+#include <openbsc/debug.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/abis/ipaccess.h>
static int bts_model_hslfemto_start(struct gsm_network *net);
+static void bts_model_hslfemto_e1line_bind_ops(struct e1inp_line *line);
static struct gsm_bts_model model_hslfemto = {
.type = GSM_BTS_TYPE_HSL_FEMTO,
.start = bts_model_hslfemto_start,
+ .e1line_bind_ops = &bts_model_hslfemto_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
/* no HSL specific OML attributes that we know of */
@@ -98,20 +103,20 @@ static int hslfemto_bootstrap_om(struct gsm_bts *bts)
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(l1_msg));
memcpy(msg->data, l1_msg, sizeof(l1_msg));
- msg->trx = bts->c0;
+ msg->dst = bts->c0->rsl_link;
abis_rsl_sendmsg(msg);
#if 1
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(conn_trau_msg));
memcpy(msg->data, conn_trau_msg, sizeof(conn_trau_msg));
- msg->trx = bts->c0;
+ msg->dst = bts->c0->rsl_link;
abis_rsl_sendmsg(msg);
#endif
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(conn_trau_msg2));
memcpy(msg->data, conn_trau_msg2, sizeof(conn_trau_msg2));
- msg->trx = bts->c0;
+ msg->dst = bts->c0->rsl_link;
abis_rsl_sendmsg(msg);
*((uint16_t *)oml_arfcn_bsic+10) = htons(bts->c0->arfcn);
@@ -120,8 +125,8 @@ static int hslfemto_bootstrap_om(struct gsm_bts *bts)
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(oml_arfcn_bsic));
memcpy(msg->data, oml_arfcn_bsic, sizeof(oml_arfcn_bsic));
- msg->trx = bts->c0;
- _abis_nm_sendmsg(msg, 0);
+ msg->dst = bts->c0->rsl_link;
+ abis_sendmsg(msg);
/* Delay the OPSTART until after SI have been set via RSL */
//abis_nm_opstart(bts, NM_OC_BTS, 255, 255, 255);
@@ -135,11 +140,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
- if (subsys != SS_INPUT)
+ if (subsys != SS_L_INPUT)
return 0;
switch (signal) {
- case S_INP_TEI_UP:
+ case S_L_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO)
@@ -151,6 +156,8 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
+static struct gsm_network *hsl_gsmnet;
+
static int bts_model_hslfemto_start(struct gsm_network *net)
{
model_hslfemto.features.data = &model_hslfemto._features_data[0];
@@ -159,13 +166,147 @@ static int bts_model_hslfemto_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_hslfemto, BTS_FEAT_GPRS);
gsm_btsmodel_set_feature(&model_hslfemto, BTS_FEAT_EGPRS);
- osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
+ osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
- /* Call A-bis input driver, start socket for OML and RSL. */
- return hsl_setup(net);
+ hsl_gsmnet = net;
+ return 0;
}
int bts_model_hslfemto_init(void)
{
return gsm_bts_model_register(&model_hslfemto);
}
+
+#define OML_UP 0x0001
+#define RSL_UP 0x0002
+
+struct gsm_bts *find_bts_by_serno(struct gsm_network *net, uint64_t serno)
+{
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ if (bts->type != GSM_BTS_TYPE_HSL_FEMTO)
+ continue;
+
+ if (serno == bts->hsl.serno)
+ return bts;
+ }
+ return NULL;
+}
+
+/* This function is called once the OML/RSL link becomes up. */
+static struct e1inp_sign_link *
+hsl_sign_link_up(void *unit_data, struct e1inp_line *line,
+ enum e1inp_sign_type type)
+{
+ struct hsl_unit *dev = unit_data;
+ struct gsm_bts *bts;
+
+ bts = find_bts_by_serno(hsl_gsmnet, dev->serno);
+ if (!bts) {
+ LOGP(DLINP, LOGL_ERROR, "Unable to find BTS config for "
+ "serial number %lx\n", dev->serno);
+ return NULL;
+ }
+ DEBUGP(DLINP, "Identified HSL BTS Serial Number %lx\n", dev->serno);
+
+ /* we shouldn't hardcode it, but HSL femto also hardcodes it... */
+ bts->oml_tei = 255;
+ bts->c0->rsl_tei = 0;
+ bts->oml_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
+ E1INP_SIGN_OML, bts->c0,
+ bts->oml_tei, 0);
+ bts->c0->rsl_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
+ E1INP_SIGN_RSL, bts->c0,
+ bts->c0->rsl_tei, 0);
+ e1inp_event(&line->ts[E1INP_SIGN_OML-1], S_L_INP_TEI_UP, 255, 0);
+ e1inp_event(&line->ts[E1INP_SIGN_OML-1], S_L_INP_TEI_UP, 0, 0);
+ bts->ip_access.flags |= OML_UP;
+ bts->ip_access.flags |= (RSL_UP << 0);
+
+ return bts->oml_link;
+}
+
+void hsl_drop_oml(struct gsm_bts *bts)
+{
+ struct e1inp_line *line;
+
+ if (!bts->oml_link)
+ return;
+
+ line = bts->oml_link->ts->line;
+ e1inp_sign_link_destroy(bts->oml_link);
+ bts->oml_link = NULL;
+
+ e1inp_sign_link_destroy(bts->c0->rsl_link);
+ bts->c0->rsl_link = NULL;
+
+ bts->ip_access.flags = 0;
+}
+
+static void hsl_sign_link_down(struct e1inp_line *line)
+{
+ /* No matter what link went down, we close both signal links. */
+ struct e1inp_ts *ts = &line->ts[E1INP_SIGN_OML-1];
+ struct e1inp_sign_link *link;
+
+ llist_for_each_entry(link, &ts->sign.sign_links, list) {
+ struct gsm_bts *bts = link->trx->bts;
+
+ hsl_drop_oml(bts);
+ /* Yes, we only use the first element of the list. */
+ break;
+ }
+}
+
+/* This function is called if we receive one OML/RSL message. */
+static int hsl_sign_link(struct msgb *msg)
+{
+ int ret = 0;
+ struct e1inp_sign_link *link = msg->dst;
+ struct e1inp_ts *e1i_ts = link->ts;
+
+ switch (link->type) {
+ case E1INP_SIGN_OML:
+ if (!(link->trx->bts->ip_access.flags & OML_UP)) {
+ e1inp_event(e1i_ts, S_L_INP_TEI_UP,
+ link->tei, link->sapi);
+ link->trx->bts->ip_access.flags |= OML_UP;
+ }
+ ret = abis_nm_rcvmsg(msg);
+ break;
+ case E1INP_SIGN_RSL:
+ if (!(link->trx->bts->ip_access.flags &
+ (RSL_UP << link->trx->nr))) {
+ e1inp_event(e1i_ts, S_L_INP_TEI_UP,
+ link->tei, link->sapi);
+ link->trx->bts->ip_access.flags |=
+ (RSL_UP << link->trx->nr);
+ }
+ ret = abis_rsl_rcvmsg(msg);
+ break;
+ default:
+ LOGP(DLINP, LOGL_ERROR, "Unknown signal link type %d\n",
+ link->type);
+ msgb_free(msg);
+ break;
+ }
+ return ret;
+}
+
+static struct e1inp_line_ops hsl_e1inp_line_ops = {
+ .cfg = {
+ .ipa = {
+ .addr = "0.0.0.0",
+ .role = E1INP_LINE_R_BSC,
+ },
+ },
+ .sign_link_up = hsl_sign_link_up,
+ .sign_link_down = hsl_sign_link_down,
+ .sign_link = hsl_sign_link,
+};
+
+static void bts_model_hslfemto_e1line_bind_ops(struct e1inp_line *line)
+{
+ e1inp_line_bind_ops(line, &hsl_e1inp_line_ops);
+}
diff --git a/openbsc/src/libbsc/bts_init.c b/openbsc/src/libbsc/bts_init.c
index 87bdde066..693eca825 100644
--- a/openbsc/src/libbsc/bts_init.c
+++ b/openbsc/src/libbsc/bts_init.c
@@ -24,6 +24,7 @@ int bts_init(void)
bts_model_rbs2k_init();
bts_model_nanobts_init();
bts_model_hslfemto_init();
+ bts_model_nokia_site_init();
/* Your new BTS here. */
return 0;
}
diff --git a/openbsc/src/libbsc/bts_ipaccess_nanobts.c b/openbsc/src/libbsc/bts_ipaccess_nanobts.c
index e756f2a88..7ece94ee1 100644
--- a/openbsc/src/libbsc/bts_ipaccess_nanobts.c
+++ b/openbsc/src/libbsc/bts_ipaccess_nanobts.c
@@ -26,15 +26,27 @@
#include <openbsc/gsm_data.h>
#include <openbsc/signal.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/e1_input.h> /* for ipaccess_setup() */
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/abis_rsl.h>
+#include <openbsc/debug.h>
+#include <osmocom/abis/subchan_demux.h>
+#include <osmocom/abis/ipaccess.h>
+#include <osmocom/core/logging.h>
static int bts_model_nanobts_start(struct gsm_network *net);
+static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line);
static struct gsm_bts_model model_nanobts = {
.type = GSM_BTS_TYPE_NANOBTS,
.name = "nanobts",
.start = bts_model_nanobts_start,
.oml_rcvmsg = &abis_nm_rcvmsg,
+ .e1line_bind_ops = bts_model_nanobts_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
/* ip.access specifics */
@@ -352,7 +364,8 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
/* We skip NSVC1 since we only use NSVC0 */
if (nsvc->id == 1)
break;
- if (new_state->availability == NM_AVSTATE_OFF_LINE) {
+ if ((new_state->availability == NM_AVSTATE_OFF_LINE) ||
+ (new_state->availability == NM_AVSTATE_DEPENDENCY)) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
nsvc->id, 0xff,
nanobts_attr_nsvc0,
@@ -373,7 +386,8 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
static int sw_activ_rep(struct msgb *mb)
{
struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct gsm_bts *bts = mb->trx->bts;
+ struct e1inp_sign_link *sign_link = mb->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
if (!trx)
@@ -439,6 +453,8 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
+static struct gsm_network *ipaccess_gsmnet;
+
static int bts_model_nanobts_start(struct gsm_network *net)
{
model_nanobts.features.data = &model_nanobts._features_data[0];
@@ -449,11 +465,185 @@ static int bts_model_nanobts_start(struct gsm_network *net)
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
- /* Call A-bis input driver, start server sockets for OML and RSL. */
- return ipaccess_setup(net);
+ ipaccess_gsmnet = net;
+ return 0;
}
int bts_model_nanobts_init(void)
{
return gsm_bts_model_register(&model_nanobts);
}
+
+#define OML_UP 0x0001
+#define RSL_UP 0x0002
+
+static struct gsm_bts *
+find_bts_by_unitid(struct gsm_network *net, uint16_t site_id, uint16_t bts_id)
+{
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ if (!is_ipaccess_bts(bts))
+ continue;
+
+ if (bts->ip_access.site_id == site_id &&
+ bts->ip_access.bts_id == bts_id)
+ return bts;
+ }
+ return NULL;
+}
+
+/* These are exported because they are used by the VTY interface. */
+void ipaccess_drop_rsl(struct gsm_bts_trx *trx)
+{
+ if (!trx->rsl_link)
+ return;
+
+ e1inp_sign_link_destroy(trx->rsl_link);
+ trx->rsl_link = NULL;
+}
+
+void ipaccess_drop_oml(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+ struct e1inp_line *line;
+
+ if (!bts->oml_link)
+ return;
+
+ line = bts->oml_link->ts->line;
+
+ e1inp_sign_link_destroy(bts->oml_link);
+ bts->oml_link = NULL;
+
+ /* we have issues reconnecting RSL, drop everything. */
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ ipaccess_drop_rsl(trx);
+
+ bts->ip_access.flags = 0;
+}
+
+/* This function is called once the OML/RSL link becomes up. */
+static struct e1inp_sign_link *
+ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line,
+ enum e1inp_sign_type type)
+{
+ struct gsm_bts *bts;
+ struct ipaccess_unit *dev = unit_data;
+ struct e1inp_sign_link *sign_link = NULL;
+
+ bts = find_bts_by_unitid(ipaccess_gsmnet, dev->site_id, dev->bts_id);
+ if (!bts) {
+ LOGP(DLINP, LOGL_ERROR, "Unable to find BTS configuration for "
+ " %u/%u/%u, disconnecting\n", dev->site_id,
+ dev->bts_id, dev->trx_id);
+ return NULL;
+ }
+ DEBUGP(DLINP, "Identified BTS %u/%u/%u\n",
+ dev->site_id, dev->bts_id, dev->trx_id);
+
+ switch(type) {
+ case E1INP_SIGN_OML:
+ /* remove old OML signal link for this BTS. */
+ ipaccess_drop_oml(bts);
+
+ /* create new OML link. */
+ sign_link = bts->oml_link =
+ e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1],
+ E1INP_SIGN_OML, bts->c0,
+ bts->oml_tei, 0);
+ break;
+ case E1INP_SIGN_RSL: {
+ struct e1inp_ts *ts;
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, dev->trx_id);
+
+ /* no OML link set yet? give up. */
+ if (!bts->oml_link)
+ return NULL;
+
+ /* remove old RSL link for this TRX. */
+ ipaccess_drop_rsl(trx);
+
+ /* set new RSL link for this TRX. */
+ line = bts->oml_link->ts->line;
+ ts = &line->ts[E1INP_SIGN_RSL + dev->trx_id - 1];
+ e1inp_ts_config_sign(ts, line);
+ sign_link = trx->rsl_link =
+ e1inp_sign_link_create(ts, E1INP_SIGN_RSL,
+ trx, trx->rsl_tei, 0);
+ trx->rsl_link->ts->sign.delay = 0;
+ break;
+ }
+ default:
+ break;
+ }
+ return sign_link;
+}
+
+static void ipaccess_sign_link_down(struct e1inp_line *line)
+{
+ /* No matter what link went down, we close both signal links. */
+ struct e1inp_ts *ts = &line->ts[E1INP_SIGN_OML-1];
+ struct e1inp_sign_link *link;
+
+ llist_for_each_entry(link, &ts->sign.sign_links, list) {
+ struct gsm_bts *bts = link->trx->bts;
+
+ ipaccess_drop_oml(bts);
+ /* Yes, we only use the first element of the list. */
+ break;
+ }
+}
+
+/* This function is called if we receive one OML/RSL message. */
+static int ipaccess_sign_link(struct msgb *msg)
+{
+ int ret = 0;
+ struct e1inp_sign_link *link = msg->dst;
+ struct e1inp_ts *e1i_ts = link->ts;
+
+ switch (link->type) {
+ case E1INP_SIGN_RSL:
+ if (!(link->trx->bts->ip_access.flags &
+ (RSL_UP << link->trx->nr))) {
+ e1inp_event(e1i_ts, S_L_INP_TEI_UP,
+ link->tei, link->sapi);
+ link->trx->bts->ip_access.flags |=
+ (RSL_UP << link->trx->nr);
+ }
+ ret = abis_rsl_rcvmsg(msg);
+ break;
+ case E1INP_SIGN_OML:
+ if (!(link->trx->bts->ip_access.flags & OML_UP)) {
+ e1inp_event(e1i_ts, S_L_INP_TEI_UP,
+ link->tei, link->sapi);
+ link->trx->bts->ip_access.flags |= OML_UP;
+ }
+ ret = abis_nm_rcvmsg(msg);
+ break;
+ default:
+ LOGP(DLINP, LOGL_ERROR, "Unknown signal link type %d\n",
+ link->type);
+ msgb_free(msg);
+ break;
+ }
+ return ret;
+}
+
+/* not static, ipaccess-config needs it. */
+struct e1inp_line_ops ipaccess_e1inp_line_ops = {
+ .cfg = {
+ .ipa = {
+ .addr = "0.0.0.0",
+ .role = E1INP_LINE_R_BSC,
+ },
+ },
+ .sign_link_up = ipaccess_sign_link_up,
+ .sign_link_down = ipaccess_sign_link_down,
+ .sign_link = ipaccess_sign_link,
+};
+
+static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line)
+{
+ e1inp_line_bind_ops(line, &ipaccess_e1inp_line_ops);
+}
diff --git a/openbsc/src/libbsc/bts_nokia_site.c b/openbsc/src/libbsc/bts_nokia_site.c
new file mode 100644
index 000000000..cb1a9d541
--- /dev/null
+++ b/openbsc/src/libbsc/bts_nokia_site.c
@@ -0,0 +1,1740 @@
+/* Nokia XXXsite family specific code */
+
+/* (C) 2011 by Dieter Spaar <spaar@mirider.augusta.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ TODO: Attention: There are some static variables used for states during
+ configuration. Those variables have to be moved to a BTS specific context,
+ otherwise there will most certainly be problems if more than one Nokia BTS
+ is used.
+*/
+
+#include <time.h>
+
+#include <osmocom/gsm/tlv.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/abis_nm.h>
+#include <osmocom/abis/e1_input.h>
+#include <openbsc/signal.h>
+
+#include <osmocom/core/timer.h>
+
+#include <osmocom/abis/lapd.h>
+
+/* TODO: put in a separate file ? */
+
+#define RESET_INTERVAL 15, 0 /* 15 seconds */
+
+extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg);
+/* was static in system_information.c */
+extern int generate_cell_chan_list(uint8_t * chan_list, struct gsm_bts *bts);
+
+static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts);
+static void reset_timer_cb(void *_bts);
+static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref);
+static int dump_elements(uint8_t * data, int len);
+
+static void bootstrap_om_bts(struct gsm_bts *bts)
+{
+ LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
+
+ if (!bts->nokia.skip_reset) {
+ if (!bts->nokia.did_reset)
+ abis_nm_reset(bts, 1);
+ } else
+ bts->nokia.did_reset = 1;
+}
+
+static void bootstrap_om_trx(struct gsm_bts_trx *trx)
+{
+ LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
+ trx->bts->nr, trx->nr);
+}
+
+static int shutdown_om(struct gsm_bts *bts)
+{
+ /* TODO !? */
+ return 0;
+}
+
+#define SAPI_OML 62
+#define SAPI_RSL 0
+
+/*
+
+ Tell LAPD to start start the SAP (send SABM requests) for all signalling
+ timeslots in this line
+
+ Attention: this has to be adapted for mISDN
+*/
+
+static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
+{
+ struct e1inp_sign_link *link;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
+ struct e1inp_ts *ts = &line->ts[i];
+
+ if (ts->type != E1INP_TS_TYPE_SIGN)
+ continue;
+
+ llist_for_each_entry(link, &ts->sign.sign_links, list) {
+ if (sapi != -1 && link->sapi != sapi)
+ continue;
+
+#if 0 /* debugging */
+ printf("sap start/stop (%d): %d tei=%d sapi=%d\n",
+ start, i + 1, link->tei, link->sapi);
+#endif
+
+ if (start) {
+ ts->lapd->profile.t200_sec = 1;
+ ts->lapd->profile.t200_usec = 0;
+ lapd_sap_start(ts->lapd, link->tei,
+ link->sapi);
+ } else
+ lapd_sap_stop(ts->lapd, link->tei,
+ link->sapi);
+ }
+ }
+}
+
+/* Callback function to be called every time we receive a signal from INPUT */
+static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct gsm_bts *bts;
+
+ if (subsys != SS_L_GLOBAL)
+ return 0;
+
+ switch (signal) {
+ case S_GLOBAL_BTS_CLOSE_OM:
+ bts = signal_data;
+ if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
+ shutdown_om(signal_data);
+ break;
+ }
+
+ return 0;
+}
+
+/* Callback function to be called every time we receive a signal from INPUT */
+static int inp_sig_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct input_signal_data *isd = signal_data;
+
+ if (subsys != SS_L_INPUT)
+ return 0;
+
+ switch (signal) {
+ case S_L_INP_LINE_INIT:
+ start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
+ break;
+ case S_L_INP_TEI_DN:
+ break;
+ case S_L_INP_TEI_UP:
+ switch (isd->link_type) {
+ case E1INP_SIGN_OML:
+ if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
+ break;
+
+ if (isd->tei == isd->trx->bts->oml_tei)
+ bootstrap_om_bts(isd->trx->bts);
+ else
+ bootstrap_om_trx(isd->trx);
+ break;
+ }
+ break;
+ case S_L_INP_TEI_UNKNOWN:
+ /* We are receiving LAPD frames with one TEI that we do not
+ * seem to know, likely that we (the BSC) stopped working
+ * and lost our local states. However, the BTS is already
+ * configured, we try to take over the RSL links. */
+ start_sabm_in_line(isd->line, 1, SAPI_RSL);
+ break;
+ }
+
+ return 0;
+}
+
+static void nm_statechg_evt(unsigned int signal,
+ struct nm_statechg_signal_data *nsd)
+{
+ if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
+ return;
+}
+
+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;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* TODO: put in a separate file ? */
+
+static const struct value_string nokia_msgt_name[] = {
+ { 0x80, "NOKIA_BTS_CONF_DATA" },
+ { 0x81, "NOKIA_BTS_ACK" },
+ { 0x82, "NOKIA_BTS_OMU_STARTED" },
+ { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" },
+ { 0x84, "NOKIA_BTS_MF_REQ" },
+ { 0x85, "NOKIA_BTS_AF_REQ" },
+ { 0x86, "NOKIA_BTS_RESET_REQ" },
+ { 0x87, "NOKIA_reserved" },
+ { 0x88, "NOKIA_BTS_CONF_REQ" },
+ { 0x89, "NOKIA_BTS_TEST_REQ" },
+ { 0x8A, "NOKIA_BTS_TEST_REPORT" },
+ { 0x8B, "NOKIA_reserved" },
+ { 0x8C, "NOKIA_reserved" },
+ { 0x8D, "NOKIA_reserved" },
+ { 0x8E, "NOKIA_BTS_CONF_COMPL" },
+ { 0x8F, "NOKIA_reserved" },
+ { 0x90, "NOKIA_BTS_STM_TEST_REQ" },
+ { 0x91, "NOKIA_BTS_STM_TEST_REPORT" },
+ { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" },
+ { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" },
+ { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" },
+ { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" },
+ { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" },
+ { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" },
+ { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" },
+ { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" },
+ { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" },
+ { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" },
+ { 0x9C, "NOKIA_BTS_HW_REQ" },
+ { 0x9D, "NOKIA_BTS_HW_REPORT" },
+ { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" },
+ { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" },
+ { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" },
+ { 0xA1, "NOKIA_BTS_CLOCK_REQ" },
+ { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" },
+ { 0xA3, "NOKIA_AC_INTERRUPTED" },
+ { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" },
+ { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" },
+ { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" },
+ { 0xA7, "NOKIA_AC_CIRCUIT_REQ" },
+ { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" },
+ { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" },
+ { 0xAA, "NOKIA_BTS_GSM_TIME" },
+ { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" },
+ { 0xAC, "NOKIA_BTS_STATE_CHANGED" },
+ { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" },
+ { 0xAE, "NOKIA_BTS_ALARM" },
+ { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" },
+ { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" },
+ { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" },
+ { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" },
+ { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" },
+ { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" },
+ { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" },
+ { 0xB6, "NOKIA_BTS_LCS_COMMAND" },
+ { 0xB7, "NOKIA_BTS_LCS_ANSWER" },
+ { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" },
+ { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" },
+ { 0, NULL }
+};
+
+static const char *get_msg_type_name_string(uint8_t msg_type)
+{
+ return get_value_string(nokia_msgt_name, msg_type);
+}
+
+static const struct value_string nokia_element_name[] = {
+ { 0x01, "Ny1" },
+ { 0x02, "T3105_F" },
+ { 0x03, "Interference band limits" },
+ { 0x04, "Interference report timer in secs" },
+ { 0x05, "Channel configuration per TS" },
+ { 0x06, "BSIC" },
+ { 0x07, "RACH report timer in secs" },
+ { 0x08, "Hardware database status" },
+ { 0x09, "BTS RX level" },
+ { 0x0A, "ARFN" },
+ { 0x0B, "STM antenna attenuation" },
+ { 0x0C, "Cell allocation bitmap" },
+ { 0x0D, "Radio definition per TS" },
+ { 0x0E, "Frame number" },
+ { 0x0F, "Antenna diversity" },
+ { 0x10, "T3105_D" },
+ { 0x11, "File format" },
+ { 0x12, "Last File" },
+ { 0x13, "BTS type" },
+ { 0x14, "Erasure mode" },
+ { 0x15, "Hopping mode" },
+ { 0x16, "Floating TRX" },
+ { 0x17, "Power supplies" },
+ { 0x18, "Reset type" },
+ { 0x19, "Averaging period" },
+ { 0x1A, "RBER2" },
+ { 0x1B, "LAC" },
+ { 0x1C, "CI" },
+ { 0x1D, "Failure parameters" },
+ { 0x1E, "(RF max power reduction)" },
+ { 0x1F, "Measured RX_SENS" },
+ { 0x20, "Extended cell radius" },
+ { 0x21, "reserved" },
+ { 0x22, "Success-Failure" },
+ { 0x23, "Ack-Nack" },
+ { 0x24, "OMU test results" },
+ { 0x25, "File identity" },
+ { 0x26, "Generation and version code" },
+ { 0x27, "SW description" },
+ { 0x28, "BCCH LEV" },
+ { 0x29, "Test type" },
+ { 0x2A, "Subscriber number" },
+ { 0x2B, "reserved" },
+ { 0x2C, "HSN" },
+ { 0x2D, "reserved" },
+ { 0x2E, "MS RXLEV" },
+ { 0x2F, "MS TXLEV" },
+ { 0x30, "RXQUAL" },
+ { 0x31, "RX SENS" },
+ { 0x32, "Alarm block" },
+ { 0x33, "Neighbouring BCCH levels" },
+ { 0x34, "STM report type" },
+ { 0x35, "MA" },
+ { 0x36, "MAIO" },
+ { 0x37, "H_FLAG" },
+ { 0x38, "TCH_ARFN" },
+ { 0x39, "Clock output" },
+ { 0x3A, "Transmitted power" },
+ { 0x3B, "Clock sync" },
+ { 0x3C, "TMS protocol discriminator" },
+ { 0x3D, "TMS protocol data" },
+ { 0x3E, "FER" },
+ { 0x3F, "SWR result" },
+ { 0x40, "Object identity" },
+ { 0x41, "STM RX Antenna Test" },
+ { 0x42, "reserved" },
+ { 0x43, "reserved" },
+ { 0x44, "Object current state" },
+ { 0x45, "reserved" },
+ { 0x46, "FU channel configuration" },
+ { 0x47, "reserved" },
+ { 0x48, "ARFN of a CU" },
+ { 0x49, "FU radio definition" },
+ { 0x4A, "reserved" },
+ { 0x4B, "Severity" },
+ { 0x4C, "Diversity selection" },
+ { 0x4D, "RX antenna test" },
+ { 0x4E, "RX antenna supervision period" },
+ { 0x4F, "RX antenna state" },
+ { 0x50, "Sector configuration" },
+ { 0x51, "Additional info" },
+ { 0x52, "SWR parameters" },
+ { 0x53, "HW inquiry mode" },
+ { 0x54, "reserved" },
+ { 0x55, "Availability status" },
+ { 0x56, "reserved" },
+ { 0x57, "EAC inputs" },
+ { 0x58, "EAC outputs" },
+ { 0x59, "reserved" },
+ { 0x5A, "Position" },
+ { 0x5B, "HW unit identity" },
+ { 0x5C, "RF test signal attenuation" },
+ { 0x5D, "Operational state" },
+ { 0x5E, "Logical object identity" },
+ { 0x5F, "reserved" },
+ { 0x60, "BS_TXPWR_OM" },
+ { 0x61, "Loop_Duration" },
+ { 0x62, "LNA_Path_Selection" },
+ { 0x63, "Serial number" },
+ { 0x64, "HW version" },
+ { 0x65, "Obj. identity and obj. state" },
+ { 0x66, "reserved" },
+ { 0x67, "EAC input definition" },
+ { 0x68, "EAC id and text" },
+ { 0x69, "HW unit status" },
+ { 0x6A, "SW release version" },
+ { 0x6B, "FW version" },
+ { 0x6C, "Bit_Error_Ratio" },
+ { 0x6D, "RXLEV_with_Attenuation" },
+ { 0x6E, "RXLEV_without_Attenuation" },
+ { 0x6F, "reserved" },
+ { 0x70, "CU_Results" },
+ { 0x71, "reserved" },
+ { 0x72, "LNA_Path_Results" },
+ { 0x73, "RTE Results" },
+ { 0x74, "Real Time" },
+ { 0x75, "RX diversity selection" },
+ { 0x76, "EAC input config" },
+ { 0x77, "Feature support" },
+ { 0x78, "File version" },
+ { 0x79, "Outputs" },
+ { 0x7A, "FU parameters" },
+ { 0x7B, "Diagnostic info" },
+ { 0x7C, "FU BSIC" },
+ { 0x7D, "TRX Configuration" },
+ { 0x7E, "Download status" },
+ { 0x7F, "RX difference limit" },
+ { 0x80, "TRX HW capability" },
+ { 0x81, "Common HW config" },
+ { 0x82, "Autoconfiguration pool size" },
+ { 0x83, "TRE diagnostic info" },
+ { 0x84, "TRE object identity" },
+ { 0x85, "New TRE Info" },
+ { 0x86, "Acknowledgement period" },
+ { 0x87, "Synchronization mode" },
+ { 0x88, "reserved" },
+ { 0x89, "Block Control Data" },
+ { 0x8A, "SW load mode" },
+ { 0x8B, "Recommended recovery action" },
+ { 0x8C, "BSC BCF id" },
+ { 0x8D, "Q1 baud rate" },
+ { 0x8E, "Allocation status" },
+ { 0x8F, "Functional entity number" },
+ { 0x90, "Transmission delay" },
+ { 0x91, "Loop Duration ms" },
+ { 0x92, "Logical channel" },
+ { 0x93, "Q1 address" },
+ { 0x94, "Alarm detail" },
+ { 0x95, "Cabinet type" },
+ { 0x96, "HW unit existence" },
+ { 0x97, "RF power parameters" },
+ { 0x98, "Message scenario" },
+ { 0x99, "HW unit max amount" },
+ { 0x9A, "Master TRX" },
+ { 0x9B, "Transparent data" },
+ { 0x9C, "BSC topology info" },
+ { 0x9D, "Air i/f modulation" },
+ { 0x9E, "LCS Q1 command data" },
+ { 0x9F, "Frame number offset" },
+ { 0xA0, "Abis TSL" },
+ { 0xA1, "Dynamic pool info" },
+ { 0xA2, "LCS LLP data" },
+ { 0xA3, "LCS Q1 answer data" },
+ { 0xA4, "DFCA FU Radio Definition" },
+ { 0xA5, "Antenna hopping" },
+ { 0xA6, "Field record sequence number" },
+ { 0xA7, "Timeslot offslot" },
+ { 0xA8, "EPCR capability" },
+ { 0xA9, "Connectsite optional element" },
+ { 0xAA, "TSC" },
+ { 0xAB, "Special TX Power Setting" },
+ { 0xAC, "Optional sync settings" },
+ { 0xFA, "Abis If parameters" },
+ { 0, NULL }
+};
+
+static const char *get_element_name_string(uint16_t element)
+{
+ return get_value_string(nokia_element_name, element);
+}
+
+static const struct value_string nokia_bts_types[] = {
+ { 0x0a, "MetroSite GSM 900" },
+ { 0x0b, "MetroSite GSM 1800" },
+ { 0x0c, "MetroSite GSM 1900 (PCS)" },
+ { 0x0d, "MetroSite GSM 900 & 1800" },
+ { 0x0e, "InSite GSM 900" },
+ { 0x0f, "InSite GSM 1800" },
+ { 0x10, "InSite GSM 1900" },
+ { 0x11, "UltraSite GSM 900" },
+ { 0x12, "UltraSite GSM 1800" },
+ { 0x13, "UltraSite GSM/US-TDMA 1900" },
+ { 0x14, "UltraSite GSM 900 & 1800" },
+ { 0x16, "UltraSite GSM/US-TDMA 850" },
+ { 0x18, "MetroSite GSM/US-TDMA 850" },
+ { 0x19, "UltraSite GSM 800/1900" },
+ { 0, NULL }
+};
+
+static const char *get_bts_type_string(uint8_t type)
+{
+ return get_value_string(nokia_bts_types, type);
+}
+
+static const struct value_string nokia_severity[] = {
+ { 0, "indeterminate" },
+ { 1, "critical" },
+ { 2, "major" },
+ { 3, "minor" },
+ { 4, "warning" },
+ { 0, NULL }
+};
+
+static const char *get_severity_string(uint8_t severity)
+{
+ return get_value_string(nokia_severity, severity);
+}
+
+/* TODO: put in a separate file ? */
+
+/* some message IDs */
+
+#define NOKIA_MSG_CONF_DATA 128
+#define NOKIA_MSG_ACK 129
+#define NOKIA_MSG_OMU_STARTED 130
+#define NOKIA_MSG_START_DOWNLOAD_REQ 131
+#define NOKIA_MSG_MF_REQ 132
+#define NOKIA_MSG_RESET_REQ 134
+#define NOKIA_MSG_CONF_REQ 136
+#define NOKIA_MSG_CONF_COMPLETE 142
+#define NOKIA_MSG_BLOCK_CTRL_REQ 168
+#define NOKIA_MSG_STATE_CHANGED 172
+#define NOKIA_MSG_ALARM 174
+
+/* some element IDs */
+
+#define NOKIA_EI_BTS_TYPE 0x13
+#define NOKIA_EI_ACK 0x23
+#define NOKIA_EI_ADD_INFO 0x51
+#define NOKIA_EI_SEVERITY 0x4B
+#define NOKIA_EI_ALARM_DETAIL 0x94
+
+#define OM_ALLOC_SIZE 1024
+#define OM_HEADROOM_SIZE 128
+
+static uint8_t fu_config_template[] = {
+ 0x7F, 0x7A, 0x39,
+ /* ID = 0x7A (FU parameters) ## constructed ## */
+ /* length = 57 */
+ /* [3] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [6] */
+ 0x00, 0x07, 0x01, 0xFF,
+
+ 0x41, 0x02,
+ /* ID = 0x01 (Ny1) */
+ /* length = 2 */
+ /* [12] */
+ 0x00, 0x05,
+
+ 0x42, 0x02,
+ /* ID = 0x02 (T3105_F) */
+ /* length = 2 */
+ /* [16] */
+ 0x00, 0x28,
+
+ 0x50, 0x02,
+ /* ID = 0x10 (T3105_D) */
+ /* length = 2 */
+ /* [20] */
+ 0x00, 0x28,
+
+ 0x43, 0x05,
+ /* ID = 0x03 (Interference band limits) */
+ /* length = 5 */
+ /* [24] */
+ 0x0F, 0x1B, 0x27, 0x33, 0x3F,
+
+ 0x44, 0x02,
+ /* ID = 0x04 (Interference report timer in secs) */
+ /* length = 2 */
+ /* [31] */
+ 0x00, 0x10,
+
+ 0x47, 0x01,
+ /* ID = 0x07 (RACH report timer in secs) */
+ /* length = 1 */
+ /* [35] */
+ 0x1E,
+
+ 0x4C, 0x10,
+ /* ID = 0x0C (Cell allocation bitmap) ####### */
+ /* length = 16 */
+ /* [38] */
+ 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x59, 0x01,
+ /* ID = 0x19 (Averaging period) */
+ /* length = 1 */
+ /* [56] */
+ 0x01,
+
+ 0x5E, 0x01,
+ /* ID = 0x1E ((RF max power reduction)) */
+ /* length = 1 */
+ /* [59] */
+ 0x00,
+
+ 0x7F, 0x46, 0x11,
+ /* ID = 0x46 (FU channel configuration) ## constructed ## */
+ /* length = 17 */
+ /* [63] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [66] */
+ 0x00, 0x07, 0x01, 0xFF,
+
+ 0x45, 0x08,
+ /* ID = 0x05 (Channel configuration per TS) */
+ /* length = 8 */
+ /* [72] */
+ 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+
+ 0x7F, 0x65, 0x0B,
+ /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
+ /* length = 11 */
+ /* [83] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [86] */
+ 0x00, 0x04, 0x01, 0xFF,
+
+ 0x5F, 0x44, 0x01,
+ /* ID = 0x44 (Object current state) */
+ /* length = 1 */
+ /* [93] */
+ 0x03,
+
+ 0x7F, 0x7C, 0x0A,
+ /* ID = 0x7C (FU BSIC) ## constructed ## */
+ /* length = 10 */
+ /* [97] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [100] */
+ 0x00, 0x07, 0x01, 0xFF,
+
+ 0x46, 0x01,
+ /* ID = 0x06 (BSIC) */
+ /* length = 1 */
+ /* [106] */
+ 0x00,
+
+ 0x7F, 0x48, 0x0B,
+ /* ID = 0x48 (ARFN of a CU) ## constructed ## */
+ /* length = 11 */
+ /* [110] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [113] */
+ 0x00, 0x08, 0x01, 0xFF,
+
+ 0x4A, 0x02,
+ /* ID = 0x0A (ARFN) ####### */
+ /* length = 2 */
+ /* [119] */
+ 0x03, 0x62,
+
+ 0x7F, 0x49, 0x59,
+ /* ID = 0x49 (FU radio definition) ## constructed ## */
+ /* length = 89 */
+ /* [124] */
+
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [127] */
+ 0x00, 0x07, 0x01, 0xFF,
+
+ 0x4D, 0x50,
+ /* ID = 0x0D (Radio definition per TS) ####### */
+ /* length = 80 */
+ /* [133] */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
+ 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x62,
+};
+
+/* TODO: put in a separate file ? */
+
+/*
+ build the configuration for each TRX
+*/
+
+static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id,
+ uint8_t * fu_config, int *hopping)
+{
+ int i;
+
+ *hopping = 0;
+
+ memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
+
+ /* set ID */
+
+ fu_config[6 + 2] = id;
+ fu_config[66 + 2] = id;
+ fu_config[86 + 2] = id;
+ fu_config[100 + 2] = id;
+ fu_config[113 + 2] = id;
+ fu_config[127 + 2] = id;
+
+ /* set ARFCN */
+
+ uint16_t arfcn = trx->arfcn;
+
+ fu_config[119] = arfcn >> 8;
+ fu_config[119 + 1] = arfcn & 0xFF;
+
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+
+ if (ts->hopping.enabled) {
+ /* reverse order */
+ int j;
+ for (j = 0; j < ts->hopping.ma_len; j++)
+ fu_config[133 + (i * 10) + (7 - j)] =
+ ts->hopping.ma_data[j];
+ fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
+ fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
+ *hopping = 1;
+ } else {
+ fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
+ fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
+ }
+ }
+
+ /* set BSIC */
+
+ /*
+ Attention: all TRX except the first one seem to get the TSC
+ from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
+ GSM 04.08 CHANNEL DESCRIPTION).
+ There was a bug in rsl_chan_activate_lchan() setting this parameter.
+ */
+
+ uint8_t bsic = trx->bts->bsic;
+
+ fu_config[106] = bsic;
+
+ /* set CA */
+
+ if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
+ fprintf(stderr, "generate_cell_chan_list failed\n");
+ return 0;
+ }
+
+ /* set channel configuration */
+
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+ uint8_t chan_config;
+
+ /*
+ 0 = FCCH + SCH + BCCH + CCCH
+ 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
+ 2 = BCCH + CCCH (This combination is not used in any BTS)
+ 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
+ 4 = SDCCH/8 + SACCH/8
+ 5 = SDCCH/8 with SDCCH2 used as CBCH
+ 6 = TCH/F + FACCH/F + SACCH/F
+ 7 = E-RACH (Talk family)
+ 9 = Dual rate (capability for TCH/F and TCH/H)
+ 10 = reserved for BTS internal use
+ 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2).
+ 0xFF = spare TS
+ */
+
+ if (ts->pchan == GSM_PCHAN_NONE)
+ chan_config = 0xFF;
+ else if (ts->pchan == GSM_PCHAN_CCCH)
+ chan_config = 0;
+ else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
+ chan_config = 1;
+ else if (ts->pchan == GSM_PCHAN_TCH_F)
+ chan_config = 6; /* 9 should work too */
+ else if (ts->pchan == GSM_PCHAN_TCH_H)
+ chan_config = 9;
+ else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
+ chan_config = 4;
+ else if (ts->pchan == GSM_PCHAN_PDCH)
+ chan_config = 11;
+ else {
+ fprintf(stderr,
+ "unsupported channel config %d for timeslot %d\n",
+ ts->pchan, i);
+ return 0;
+ }
+
+ fu_config[72 + i] = chan_config;
+ }
+ return sizeof(fu_config_template);
+}
+
+/* TODO: put in a separate file ? */
+
+static uint8_t bts_config_1[] = {
+ 0x4E, 0x02,
+ /* ID = 0x0E (Frame number) */
+ /* length = 2 */
+ /* [2] */
+ 0xFF, 0xFF,
+
+ 0x5F, 0x4E, 0x02,
+ /* ID = 0x4E (RX antenna supervision period) */
+ /* length = 2 */
+ /* [7] */
+ 0xFF, 0xFF,
+
+ 0x5F, 0x50, 0x02,
+ /* ID = 0x50 (Sector configuration) */
+ /* length = 2 */
+ /* [12] */
+ 0x01, 0x01,
+};
+
+static uint8_t bts_config_2[] = {
+ 0x55, 0x02,
+ /* ID = 0x15 (Hopping mode) */
+ /* length = 2 */
+ /* [2] */
+ 0x01, 0x00,
+
+ 0x5F, 0x75, 0x02,
+ /* ID = 0x75 (RX diversity selection) */
+ /* length = 2 */
+ /* [7] */
+ 0x01, 0x01,
+};
+
+static uint8_t bts_config_3[] = {
+ 0x5F, 0x20, 0x02,
+ /* ID = 0x20 (Extended cell radius) */
+ /* length = 2 */
+ /* [3] */
+ 0x01, 0x00,
+};
+
+static uint8_t bts_config_4[] = {
+ 0x5F, 0x74, 0x09,
+ /* ID = 0x74 (Real Time) */
+ /* length = 9 */
+ /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
+ 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
+ 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [15] */
+ 0x01, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [21] */
+ 0x02, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [27] */
+ 0x03, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [33] */
+ 0x04, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [39] */
+ 0x05, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [45] */
+ 0x06, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [51] */
+ 0x07, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [57] */
+ 0x08, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [63] */
+ 0x09, 0x01, 0x00,
+
+ 0x5F, 0x76, 0x03,
+ /* ID = 0x76 (EAC input config) */
+ /* length = 3 */
+ /* [69] */
+ 0x0A, 0x01, 0x00,
+};
+
+static uint8_t bts_config_insite[] = {
+ 0x4E, 0x02,
+ /* ID = 0x0E (Frame number) */
+ /* length = 2 */
+ /* [2] */
+ 0xFF, 0xFF,
+
+ 0x5F, 0x4E, 0x02,
+ /* ID = 0x4E (RX antenna supervision period) */
+ /* length = 2 */
+ /* [7] */
+ 0xFF, 0xFF,
+
+ 0x5F, 0x50, 0x02,
+ /* ID = 0x50 (Sector configuration) */
+ /* length = 2 */
+ /* [12] */
+ 0x01, 0x01,
+
+ 0x55, 0x02,
+ /* ID = 0x15 (Hopping mode) */
+ /* length = 2 */
+ /* [16] */
+ 0x01, 0x00,
+
+ 0x5F, 0x20, 0x02,
+ /* ID = 0x20 (Extended cell radius) */
+ /* length = 2 */
+ /* [21] */
+ 0x01, 0x00,
+
+ 0x5F, 0x74, 0x09,
+ /* ID = 0x74 (Real Time) */
+ /* length = 9 */
+ /* [26] */
+ 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
+ 0x00,
+};
+
+void set_real_time(uint8_t * real_time)
+{
+ time_t t;
+ struct tm *tm;
+
+ t = time(NULL);
+ tm = localtime(&t);
+
+ /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
+
+ real_time[0] = (1900 + tm->tm_year) >> 8;
+ real_time[1] = (1900 + tm->tm_year) & 0xFF;
+ real_time[2] = tm->tm_mon + 1;
+ real_time[3] = tm->tm_mday;
+ real_time[4] = tm->tm_hour;
+ real_time[5] = tm->tm_min;
+ real_time[6] = tm->tm_sec;
+ real_time[7] = 0;
+ real_time[8] = 0;
+}
+
+/* TODO: put in a separate file ? */
+
+/*
+ build the configuration data
+*/
+
+static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config,
+ int need_hopping)
+{
+ /* is it an InSite BTS ? */
+ if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
+ if (n_trx != 1) {
+ fprintf(stderr, "InSite has only one TRX\n");
+ return 0;
+ }
+ if (need_hopping != 0) {
+ fprintf(stderr, "InSite does not support hopping\n");
+ return 0;
+ }
+ memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
+ set_real_time(&fu_config[26]);
+ return sizeof(bts_config_insite);
+ }
+
+ int len = 0;
+ int i;
+
+ memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
+
+ /* set sector configuration */
+ fu_config[len + 12 - 1] = 1 + n_trx; /* len */
+ for (i = 0; i < n_trx; i++)
+ fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
+
+ len += (sizeof(bts_config_1) + (n_trx - 1));
+
+ memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
+ /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
+ if (need_hopping)
+ fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
+ len += sizeof(bts_config_2);
+
+ /* set extended cell radius for each TRX */
+ for (i = 0; i < n_trx; i++) {
+ memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
+ fu_config[len + 3] = ((i + 1) & 0xFF);
+ len += sizeof(bts_config_3);
+ }
+
+ memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
+ set_real_time(&fu_config[len + 3]);
+ len += sizeof(bts_config_4);
+
+ return len;
+}
+
+/* TODO: put in a separate file ? */
+
+static struct msgb *nm_msgb_alloc(void)
+{
+ return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
+}
+
+/* TODO: put in a separate file ? */
+
+struct abis_om_nokia_hdr {
+ uint8_t msg_type;
+ uint8_t spare;
+ uint16_t reference;
+ uint8_t data[0];
+} __attribute__ ((packed));
+
+#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
+
+static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref,
+ uint8_t * data, int len_data)
+{
+ struct abis_om_hdr *oh;
+ struct abis_om_nokia_hdr *noh;
+ struct msgb *msg = nm_msgb_alloc();
+
+ oh = (struct abis_om_hdr *)msgb_put(msg,
+ ABIS_OM_NOKIA_HDR_SIZE + len_data);
+
+ oh->mdisc = ABIS_OM_MDISC_FOM;
+ oh->placement = ABIS_OM_PLACEMENT_ONLY;
+ oh->sequence = 0;
+ oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
+
+ noh = (struct abis_om_nokia_hdr *)oh->data;
+
+ noh->msg_type = msg_type;
+ noh->spare = 0;
+ noh->reference = htons(ref);
+ memcpy(noh->data, data, len_data);
+
+ DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
+
+ return abis_nm_sendmsg(bts, msg);
+}
+
+/* TODO: put in a separate file ? */
+
+static uint8_t download_req[] = {
+ 0x5F, 0x25, 0x0B,
+ /* ID = 0x25 (File identity) */
+ /* length = 11 */
+ /* [3] */
+ 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
+ 0x2A, 0x2A, 0x2A,
+
+ 0x5F, 0x78, 0x03,
+ /* ID = 0x78 (File version) */
+ /* length = 3 */
+ /* [17] */
+ 0x2A, 0x2A, 0x2A,
+
+ 0x5F, 0x81, 0x0A, 0x01,
+ /* ID = 0x8A (SW load mode) */
+ /* length = 1 */
+ /* [24] */
+ 0x01,
+
+ 0x5F, 0x81, 0x06, 0x01,
+ /* ID = 0x86 (Acknowledgement period) */
+ /* length = 1 */
+ /* [29] */
+ 0x01,
+};
+
+static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
+{
+ uint8_t *data = download_req;
+ int len_data = sizeof(download_req);
+
+ return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data,
+ len_data);
+}
+
+/* TODO: put in a separate file ? */
+
+static uint8_t ack[] = {
+ 0x5F, 0x23, 0x01,
+ /* ID = 0x23 (Ack-Nack) */
+ /* length = 1 */
+ /* [3] */
+ 0x01,
+};
+
+static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
+{
+ uint8_t *data = ack;
+ int len_data = sizeof(ack);
+
+ return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
+}
+
+/* TODO: put in a separate file ? */
+
+static uint8_t reset[] = {
+ 0x5F, 0x40, 0x04,
+ /* ID = 0x40 (Object identity) */
+ /* length = 4 */
+ /* [3] */
+ 0x00, 0x01, 0xFF, 0xFF,
+};
+
+static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
+{
+ uint8_t *data = reset;
+ int len_data = sizeof(reset);
+
+ return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
+}
+
+/* TODO: put in a separate file ? */
+
+static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type,
+ uint16_t ref, uint8_t * data, int len)
+{
+ int len_remain, len_to_send, max_send;
+ int seq = 0;
+ int ret;
+
+ len_remain = len;
+
+ while (len_remain) {
+ struct abis_om_hdr *oh;
+ struct abis_om_nokia_hdr *noh;
+ struct msgb *msg = nm_msgb_alloc();
+
+ if (seq == 0)
+ max_send = 256 - sizeof(struct abis_om_nokia_hdr);
+ else
+ max_send = 256;
+
+ if (len_remain > max_send) {
+ len_to_send = max_send;
+
+ if (seq == 0) {
+ /* first segment */
+ oh = (struct abis_om_hdr *)msgb_put(msg,
+ ABIS_OM_NOKIA_HDR_SIZE
+ +
+ len_to_send);
+
+ oh->mdisc = ABIS_OM_MDISC_FOM;
+ oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
+ oh->sequence = seq;
+ oh->length = 0; /* 256 bytes */
+
+ noh = (struct abis_om_nokia_hdr *)oh->data;
+
+ noh->msg_type = msg_type;
+ noh->spare = 0;
+ noh->reference = htons(ref);
+ memcpy(noh->data, data, len_to_send);
+ } else {
+ /* segment in between */
+ oh = (struct abis_om_hdr *)msgb_put(msg,
+ sizeof
+ (struct
+ abis_om_hdr)
+ +
+ len_to_send);
+
+ oh->mdisc = ABIS_OM_MDISC_FOM;
+ oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
+ oh->sequence = seq;
+ oh->length = 0; /* 256 bytes */
+
+ memcpy(oh->data, data, len_to_send);
+ }
+ } else {
+
+ len_to_send = len_remain;
+
+ /* check if message fits in a single segment */
+
+ if (seq == 0)
+ return abis_nm_send(bts, msg_type, ref, data,
+ len_to_send);
+
+ /* last segment */
+
+ oh = (struct abis_om_hdr *)msgb_put(msg,
+ sizeof(struct
+ abis_om_hdr)
+ + len_to_send);
+
+ oh->mdisc = ABIS_OM_MDISC_FOM;
+ oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
+ oh->sequence = seq;
+ oh->length = len_to_send;
+
+ memcpy(oh->data, data, len_to_send);
+ }
+
+ DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
+
+ ret = abis_nm_sendmsg(bts, msg);
+ if (ret < 0)
+ return ret;
+
+ nokia_abis_nm_queue_send_next(bts);
+
+ /* next segment */
+ len_remain -= len_to_send;
+ data += len_to_send;
+ seq++;
+ }
+ return ret;
+}
+
+/* TODO: put in a separate file ? */
+
+static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
+{
+ struct gsm_bts_trx *trx;
+ uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
+ int len = 0;
+ int idx = 0;
+ int ret;
+ int hopping = 0;
+ int need_hopping = 0;
+
+ memset(config, 0, sizeof(config));
+
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+#if 0 /* debugging */
+ printf("TRX\n");
+ printf(" arfcn: %d\n", trx->arfcn);
+ printf(" bsic: %d\n", trx->bts->bsic);
+ uint8_t ca[20];
+ memset(ca, 0xFF, sizeof(ca));
+ ret = generate_cell_chan_list(ca, trx->bts);
+ printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
+ int i;
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[i];
+
+ printf(" pchan %d: %d\n", i, ts->pchan);
+ }
+#endif
+ ret = make_fu_config(trx, idx + 1, config + len, &hopping);
+ need_hopping |= hopping;
+ len += ret;
+
+ idx++;
+ }
+
+ ret = make_bts_config(bts_type, idx, config + len, need_hopping);
+ len += ret;
+
+#if 0 /* debugging */
+ dump_elements(config, len);
+#endif
+
+ return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config,
+ len);
+}
+
+#define GET_NEXT_BYTE if(idx >= len) return 0; \
+ ub = data[idx++];
+
+static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value,
+ int max_value)
+{
+ uint8_t ub;
+ int idx = 0;
+ int found = 0;
+ int constructed;
+ uint16_t id_value;
+
+ for (;;) {
+
+ GET_NEXT_BYTE;
+
+ /* encoding bit, construced means that other elements are contained */
+ constructed = ((ub & 0x20) ? 1 : 0);
+
+ if ((ub & 0x1F) == 0x1F) {
+ /* fixed pattern, ID follows */
+ GET_NEXT_BYTE; /* ID */
+ id_value = ub & 0x7F;
+ if (ub & 0x80) {
+ /* extension bit */
+ GET_NEXT_BYTE; /* ID low part */
+ id_value = (id_value << 7) | (ub & 0x7F);
+ }
+ if (id_value == id)
+ found = 1;
+ } else {
+ id_value = (ub & 0x3F);
+ if (id_value == id)
+ found = 1;
+ }
+
+ GET_NEXT_BYTE; /* length */
+
+ if (found) {
+ /* get data */
+ uint8_t n = ub;
+ uint8_t i;
+ for (i = 0; i < n; i++) {
+ GET_NEXT_BYTE;
+ if (max_value <= 0)
+ return -1; /* buffer too small */
+ *value = ub;
+ value++;
+ max_value--;
+ }
+ return n; /* length */
+ } else {
+ /* skip data */
+ uint8_t n = ub;
+ uint8_t i;
+ for (i = 0; i < n; i++) {
+ GET_NEXT_BYTE;
+ }
+ }
+ }
+ return 0; /* not found */
+}
+
+static int dump_elements(uint8_t * data, int len)
+{
+ uint8_t ub;
+ int idx = 0;
+ int constructed;
+ uint16_t id_value;
+ static char indent[100] = ""; /* TODO: move static to BTS context */
+
+ for (;;) {
+
+ GET_NEXT_BYTE;
+
+ /* encoding bit, construced means that other elements are contained */
+ constructed = ((ub & 0x20) ? 1 : 0);
+
+ if ((ub & 0x1F) == 0x1F) {
+ /* fixed pattern, ID follows */
+ GET_NEXT_BYTE; /* ID */
+ id_value = ub & 0x7F;
+ if (ub & 0x80) {
+ /* extension bit */
+ GET_NEXT_BYTE; /* ID low part */
+ id_value = (id_value << 7) | (ub & 0x7F);
+ }
+
+ } else {
+ id_value = (ub & 0x3F);
+ }
+
+ GET_NEXT_BYTE; /* length */
+
+ printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value,
+ get_element_name_string(id_value),
+ constructed ? "** constructed **" : "");
+ printf("%s length = %d\n", indent, ub);
+ printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
+
+ if (constructed) {
+ int indent_len = strlen(indent);
+ strcat(indent, " ");
+
+ dump_elements(data + idx, ub);
+
+ indent[indent_len] = 0;
+ }
+ /* skip data */
+ uint8_t n = ub;
+ uint8_t i;
+ for (i = 0; i < n; i++) {
+ GET_NEXT_BYTE;
+ }
+ }
+ return 0;
+}
+
+/* TODO: put in a separate file ? */
+
+/* taken from abis_nm.c */
+
+static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts)
+{
+ int wait = 0;
+ struct msgb *msg;
+ /* the queue is empty */
+ while (!llist_empty(&bts->abis_queue)) {
+ msg = msgb_dequeue(&bts->abis_queue);
+ wait = OBSC_NM_W_ACK_CB(msg);
+ abis_sendmsg(msg);
+
+ if (wait)
+ break;
+ }
+
+ bts->abis_nm_pend = wait;
+}
+
+/* TODO: put in a separate file ? */
+
+/* timer for restarting OML after BTS reset */
+
+static void reset_timer_cb(void *_bts)
+{
+ struct gsm_bts *bts = _bts;
+ struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
+ struct e1inp_line *line;
+
+ bts->nokia.wait_reset = 0;
+
+ /* OML link */
+ line = e1inp_line_find(e1_link->e1_nr);
+ if (!line) {
+ LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
+ "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
+ return;
+ }
+
+ start_sabm_in_line(line, 0, -1); /* stop all first */
+ start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
+}
+
+/* TODO: put in a separate file ? */
+
+/*
+ This is how the configuration is done:
+ - start OML link
+ - reset BTS
+ - receive ACK, wait some time and restart OML link
+ - receive OMU STARTED message, send START DOWNLOAD REQ
+ - receive CNF REQ message, send CONF DATA
+ - receive ACK, start RSL link(s)
+ ACK some other messages received from the BTS.
+
+ Probably its also possible to configure the BTS without a reset, this
+ has not been tested yet.
+*/
+
+static int abis_nm_rcvmsg_fom(struct msgb *mb)
+{
+ struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
+ struct abis_om_hdr *oh = msgb_l2(mb);
+ struct abis_om_nokia_hdr *noh = msgb_l3(mb);
+ uint8_t mt = noh->msg_type;
+ int ret = 0;
+ uint16_t ref = ntohs(noh->reference);
+ uint8_t info[256];
+ uint8_t ack = 0xFF;
+ uint8_t severity = 0xFF;
+ int str_len;
+ int len_data;
+
+ if (bts->nokia.wait_reset) {
+ LOGP(DNM, LOGL_INFO,
+ "Ignore message while waiting for reset\n");
+ return ret;
+ }
+
+ if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
+ LOGP(DNM, LOGL_ERROR, "Message too short\n");
+ return -EINVAL;
+ }
+
+ len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
+ LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
+#if 0 /* debugging */
+ dump_elements(noh->data, len_data);
+#endif
+
+ switch (mt) {
+ case NOKIA_MSG_OMU_STARTED:
+ if (find_element(noh->data, len_data,
+ NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type,
+ sizeof(uint8_t)) == sizeof(uint8_t))
+ LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n",
+ bts->nokia.bts_type,
+ get_bts_type_string(bts->nokia.bts_type));
+ else
+ LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
+ /* send START_DOWNLOAD_REQ */
+ abis_nm_download_req(bts, ref);
+ break;
+ case NOKIA_MSG_MF_REQ:
+ break;
+ case NOKIA_MSG_CONF_REQ:
+ /* send ACK */
+ abis_nm_ack(bts, ref);
+ nokia_abis_nm_queue_send_next(bts);
+ /* send CONF_DATA */
+ abis_nm_send_config(bts, bts->nokia.bts_type);
+ bts->nokia.configured = 1;
+ break;
+ case NOKIA_MSG_ACK:
+ if (find_element
+ (noh->data, len_data, NOKIA_EI_ACK, &ack,
+ sizeof(uint8_t)) == sizeof(uint8_t)) {
+ LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
+ if (ack != 1) {
+ LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n",
+ ack);
+ /* TODO: properly handle failures (NACK) */
+ }
+ } else
+ LOGP(DNM, LOGL_ERROR, "ACK not found\n");
+
+ /* TODO: the assumption for the following is that no NACK was received */
+
+ /* ACK for reset message ? */
+ if (!bts->nokia.did_reset) {
+ bts->nokia.did_reset = 1;
+
+ /*
+ TODO: For the InSite processing the received data is
+ blocked in the driver during reset.
+ Otherwise the LAPD module might assert because the InSite
+ sends garbage on the E1 line during reset.
+ This is done by looking at "wait_reset" in the driver
+ (function handle_ts1_read()) and ignoring the received data.
+ It seems to be necessary for the MetroSite too.
+ */
+ bts->nokia.wait_reset = 1;
+
+ bts->nokia.reset_timer.cb = &reset_timer_cb;
+ bts->nokia.reset_timer.data = bts;
+ osmo_timer_schedule(&bts->nokia.reset_timer, RESET_INTERVAL);
+
+ struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
+ struct e1inp_line *line;
+ /* OML link */
+ line = e1inp_line_find(e1_link->e1_nr);
+ if (!line) {
+ LOGP(DLINP, LOGL_ERROR,
+ "BTS %u OML link referring to "
+ "non-existing E1 line %u\n", bts->nr,
+ e1_link->e1_nr);
+ return -ENOMEM;
+ }
+
+ start_sabm_in_line(line, 0, -1); /* stop all first */
+ }
+
+ /* ACK for CONF DATA message ? */
+ if (bts->nokia.configured != 0) {
+ /* start TRX (RSL link) */
+
+ struct gsm_e1_subslot *e1_link =
+ &sign_link->trx->rsl_e1_link;
+ struct e1inp_line *line;
+
+ bts->nokia.configured = 0;
+
+ /* RSL Link */
+ line = e1inp_line_find(e1_link->e1_nr);
+ if (!line) {
+ LOGP(DLINP, LOGL_ERROR,
+ "TRX (%u/%u) RSL link referring "
+ "to non-existing E1 line %u\n",
+ sign_link->trx->bts->nr, sign_link->trx->nr,
+ e1_link->e1_nr);
+ return -ENOMEM;
+ }
+ /* start TRX */
+ start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
+ }
+ break;
+ case NOKIA_MSG_STATE_CHANGED:
+ /* send ACK */
+ abis_nm_ack(bts, ref);
+ break;
+ case NOKIA_MSG_CONF_COMPLETE:
+ /* send ACK */
+ abis_nm_ack(bts, ref);
+ break;
+ case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
+ /* send ACK (do we have to send an ACK ?) */
+ abis_nm_ack(bts, ref);
+ break;
+ case NOKIA_MSG_ALARM:
+ find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity,
+ sizeof(severity));
+ /* TODO: there might be alarms with both elements set */
+ str_len =
+ find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info,
+ sizeof(info));
+ if (str_len > 0) {
+ info[str_len] = 0;
+ LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n",
+ get_severity_string(severity), severity, info);
+ } else { /* nothing found, try details */
+ str_len =
+ find_element(noh->data, len_data,
+ NOKIA_EI_ALARM_DETAIL, info,
+ sizeof(info));
+ if (str_len > 0) {
+ uint16_t code;
+ info[str_len] = 0;
+ code = (info[0] << 8) + info[1];
+ LOGP(DNM, LOGL_INFO,
+ "ALARM Severity %s (%d), code 0x%X : %s\n",
+ get_severity_string(severity), severity,
+ code, info + 2);
+ }
+ }
+ /* send ACK */
+ abis_nm_ack(bts, ref);
+ break;
+ }
+
+ nokia_abis_nm_queue_send_next(bts);
+
+ return ret;
+}
+
+/* TODO: put in a separate file ? */
+
+int abis_nokia_rcvmsg(struct msgb *msg)
+{
+ struct abis_om_hdr *oh = msgb_l2(msg);
+ int rc = 0;
+
+ /* Various consistency checks */
+ if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
+ LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
+ oh->placement);
+ if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
+ return -EINVAL;
+ }
+ if (oh->sequence != 0) {
+ LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
+ oh->sequence);
+ return -EINVAL;
+ }
+ msg->l3h = (unsigned char *)oh + sizeof(*oh);
+
+ switch (oh->mdisc) {
+ case ABIS_OM_MDISC_FOM:
+ LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
+ rc = abis_nm_rcvmsg_fom(msg);
+ break;
+ case ABIS_OM_MDISC_MANUF:
+ LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
+ break;
+ case ABIS_OM_MDISC_MMI:
+ case ABIS_OM_MDISC_TRAU:
+ LOGP(DNM, LOGL_ERROR,
+ "unimplemented ABIS OML message discriminator 0x%x\n",
+ oh->mdisc);
+ break;
+ default:
+ LOGP(DNM, LOGL_ERROR,
+ "unknown ABIS OML message discriminator 0x%x\n",
+ oh->mdisc);
+ return -EINVAL;
+ }
+
+ msgb_free(msg);
+ return rc;
+}
+
+static int bts_model_nokia_site_start(struct gsm_network *net);
+
+static void bts_model_nokia_site_e1line_bind_ops(struct e1inp_line *line)
+{
+ e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
+}
+
+static struct gsm_bts_model model_nokia_site = {
+ .type = GSM_BTS_TYPE_NOKIA_SITE,
+ .name = "nokia_site",
+ .start = bts_model_nokia_site_start,
+ .oml_rcvmsg = &abis_nokia_rcvmsg,
+ .e1line_bind_ops = &bts_model_nokia_site_e1line_bind_ops,
+};
+
+static struct gsm_network *my_net;
+
+static int bts_model_nokia_site_start(struct gsm_network *net)
+{
+ model_nokia_site.features.data = &model_nokia_site._features_data[0];
+ model_nokia_site.features.data_len =
+ sizeof(model_nokia_site._features_data);
+
+ gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
+ gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
+
+ 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);
+
+ my_net = net;
+
+ return 0;
+}
+
+int bts_model_nokia_site_init(void)
+{
+ return gsm_bts_model_register(&model_nokia_site);
+}
diff --git a/openbsc/src/libbsc/bts_siemens_bs11.c b/openbsc/src/libbsc/bts_siemens_bs11.c
index df4a1dc23..2514d9977 100644
--- a/openbsc/src/libbsc/bts_siemens_bs11.c
+++ b/openbsc/src/libbsc/bts_siemens_bs11.c
@@ -25,16 +25,22 @@
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
-#include <openbsc/e1_input.h>
+#include <osmocom/abis/e1_input.h>
#include <openbsc/signal.h>
static int bts_model_bs11_start(struct gsm_network *net);
+static void bts_model_bs11_e1line_bind_ops(struct e1inp_line *line)
+{
+ e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
+}
+
static struct gsm_bts_model model_bs11 = {
.type = GSM_BTS_TYPE_BS11,
.name = "bs11",
.start = bts_model_bs11_start,
.oml_rcvmsg = &abis_nm_rcvmsg,
+ .e1line_bind_ops = bts_model_bs11_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
[NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV },
@@ -542,7 +548,7 @@ static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
{
struct gsm_bts *bts;
- if (subsys != SS_GLOBAL)
+ if (subsys != SS_L_GLOBAL)
return 0;
switch (signal) {
@@ -562,11 +568,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
- if (subsys != SS_INPUT)
+ if (subsys != SS_L_INPUT)
return 0;
switch (signal) {
- case S_INP_TEI_UP:
+ case S_L_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type == GSM_BTS_TYPE_BS11)
@@ -586,8 +592,8 @@ static int bts_model_bs11_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HOPPING);
gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HSCSD);
- osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
- osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
+ osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
+ osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
return 0;
}
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index c0bdc1be9..6f4fe20f8 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -299,6 +299,10 @@ void lchan_free(struct gsm_lchan *lchan)
sig.type = lchan->type;
lchan->type = GSM_LCHAN_NONE;
+ if (lchan->state != LCHAN_S_NONE) {
+ LOGP(DRLL, LOGL_NOTICE, "Freeing lchan with state %s - setting to NONE\n", gsm_lchans_name(lchan->state));
+ lchan->state = LCHAN_S_NONE;
+ }
if (lchan->conn) {
struct lchan_signal_data sig;
diff --git a/openbsc/src/libbsc/e1_config.c b/openbsc/src/libbsc/e1_config.c
index bd6ebba9d..cda131845 100644
--- a/openbsc/src/libbsc/e1_config.c
+++ b/openbsc/src/libbsc/e1_config.c
@@ -24,13 +24,14 @@
#include <netinet/in.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/trau_frame.h>
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/abis/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <openbsc/misdn.h>
-#include <openbsc/ipaccess.h>
+#include <osmocom/abis/ipaccess.h>
#include <osmocom/core/talloc.h>
#include <openbsc/debug.h>
+#include <openbsc/abis_rsl.h>
#define SAPI_L2ML 0
#define SAPI_OML 62
@@ -46,17 +47,17 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts)
struct e1inp_line *line;
struct e1inp_ts *e1_ts;
- DEBUGP(DMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr);
+ DEBUGP(DLMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr);
if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n",
+ LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n",
ts->nr, ts->trx->nr, ts->trx->bts->nr);
return 0;
}
- line = e1inp_line_get(e1_link->e1_nr);
+ line = e1inp_line_find(e1_link->e1_nr);
if (!line) {
- LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) referring to "
+ LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) referring to "
"non-existing E1 line %u\n", ts->nr, ts->trx->nr,
ts->trx->bts->nr, e1_link->e1_nr);
return -ENOMEM;
@@ -66,7 +67,7 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts)
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
e1_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(e1_ts, line, E1INP_TS_TYPE_TRAU);
+ e1inp_ts_config_trau(e1_ts, line, subch_cb);
subch_demux_activate(&e1_ts->trau.demux, e1_link->e1_ts_ss);
break;
default:
@@ -85,28 +86,28 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
int i;
if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link without "
+ LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link without "
"timeslot?\n", trx->bts->nr, trx->nr);
return -EINVAL;
}
/* RSL Link */
- line = e1inp_line_get(e1_link->e1_nr);
+ line = e1inp_line_find(e1_link->e1_nr);
if (!line) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
+ LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
"to non-existing E1 line %u\n", trx->bts->nr,
trx->nr, e1_link->e1_nr);
return -ENOMEM;
}
sign_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
+ e1inp_ts_config_sign(sign_ts, line);
/* Ericsson RBS have a per-TRX OML link in parallel to RSL */
if (trx->bts->type == GSM_BTS_TYPE_RBS2000) {
struct e1inp_sign_link *oml_link;
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, trx,
trx->rsl_tei, SAPI_OML);
if (!oml_link) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) OML link creation "
+ LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) OML link creation "
"failed\n", trx->bts->nr, trx->nr);
return -ENOMEM;
}
@@ -117,7 +118,7 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
trx, trx->rsl_tei, SAPI_RSL);
if (!rsl_link) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation "
+ LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation "
"failed\n", trx->bts->nr, trx->nr);
return -ENOMEM;
}
@@ -131,6 +132,33 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
return 0;
}
+/* this is the generic callback for all ISDN-based BTS. */
+static int bts_isdn_sign_link(struct msgb *msg)
+{
+ int ret = -EINVAL;
+ struct e1inp_sign_link *link = msg->dst;
+ struct gsm_bts *bts;
+
+ log_set_context(BSC_CTX_BTS, link->trx->bts);
+ switch (link->type) {
+ case E1INP_SIGN_OML:
+ bts = link->trx->bts;
+ ret = bts->model->oml_rcvmsg(msg);
+ break;
+ case E1INP_SIGN_RSL:
+ ret = abis_rsl_rcvmsg(msg);
+ break;
+ default:
+ LOGP(DLMI, LOGL_ERROR, "unknown link type %u\n", link->type);
+ break;
+ }
+ return ret;
+}
+
+struct e1inp_line_ops bts_isdn_e1inp_line_ops = {
+ .sign_link = bts_isdn_sign_link,
+};
+
int e1_reconfig_bts(struct gsm_bts *bts)
{
struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
@@ -139,27 +167,40 @@ int e1_reconfig_bts(struct gsm_bts *bts)
struct e1inp_sign_link *oml_link;
struct gsm_bts_trx *trx;
- DEBUGP(DMI, "e1_reconfig_bts(%u)\n", bts->nr);
+ DEBUGP(DLMI, "e1_reconfig_bts(%u)\n", bts->nr);
- if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n",
- bts->nr);
+ line = e1inp_line_find(e1_link->e1_nr);
+ if (!line) {
+ LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
+ "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
+ return -ENOMEM;
+ }
+
+ if (!bts->model->e1line_bind_ops) {
+ LOGP(DLINP, LOGL_ERROR, "no callback to bind E1 line operations\n");
return -EINVAL;
}
+ if (!line->ops)
+ bts->model->e1line_bind_ops(line);
+
+ /* skip signal link initialization, this is done later for these BTS. */
+ if (bts->type == GSM_BTS_TYPE_NANOBTS ||
+ bts->type == GSM_BTS_TYPE_HSL_FEMTO)
+ return e1inp_line_update(line);
/* OML link */
- line = e1inp_line_get(e1_link->e1_nr);
- if (!line) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
- "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
- return -ENOMEM;
+ if (!e1_link->e1_ts) {
+ LOGP(DLINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n",
+ bts->nr);
+ return -EINVAL;
}
+
sign_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
+ e1inp_ts_config_sign(sign_ts, line);
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
bts->c0, bts->oml_tei, SAPI_OML);
if (!oml_link) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link creation failed\n",
+ LOGP(DLINP, LOGL_ERROR, "BTS %u OML link creation failed\n",
bts->nr);
return -ENOMEM;
}
@@ -260,37 +301,3 @@ int e1_config(struct gsm_bts *bts, int cardnr, int release_l2)
return mi_setup(cardnr, line, release_l2);
}
#endif
-
-/* configure pseudo E1 line in ip.access style and connect to BTS */
-int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin)
-{
- struct e1inp_line *line;
- struct e1inp_ts *sign_ts, *rsl_ts;
- struct e1inp_sign_link *oml_link, *rsl_link;
-
- line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
- if (!line)
- return -ENOMEM;
-
- /* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN);
-
- /* create signalling links for TS1 */
- sign_ts = &line->ts[1-1];
- rsl_ts = &line->ts[2-1];
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- bts->c0, 0xff, 0);
- rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL,
- bts->c0, 0, 0);
-
- /* create back-links from bts/trx */
- bts->oml_link = oml_link;
- bts->c0->rsl_link = rsl_link;
-
- /* default port at BTS for incoming connections is 3006 */
- if (sin->sin_port == 0)
- sin->sin_port = htons(3006);
-
- return ipaccess_connect(line, sin);
-}
diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c
index 17bce85a6..968e62ec6 100644
--- a/openbsc/src/libbsc/gsm_04_08_utils.c
+++ b/openbsc/src/libbsc/gsm_04_08_utils.c
@@ -44,7 +44,7 @@ int ipacc_rtp_direct = 1;
static int gsm48_sendmsg(struct msgb *msg)
{
if (msg->lchan)
- msg->trx = msg->lchan->ts->trx;
+ msg->dst = msg->lchan->ts->trx->rsl_link;
msg->l3h = msg->data;
return rsl_data_request(msg, 0);
@@ -190,7 +190,7 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_network *network, uint8_t ra)
return GSM_LCHAN_SDCCH;
}
-enum gsm_chreq_reason_t get_reason_by_chreq(uint8_t ra, int neci)
+int get_reason_by_chreq(uint8_t ra, int neci)
{
int i;
int length;
diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c
index 353b3dd9b..1b0f5c9bc 100644
--- a/openbsc/src/libbsc/system_information.c
+++ b/openbsc/src/libbsc/system_information.c
@@ -154,7 +154,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
}
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
+/* static*/ int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct bitvec *bv = &bts->si_common.cell_alloc;
@@ -420,7 +420,7 @@ static struct gsm48_si13_info si13_default = {
.t3192 = 200,
.drx_timer_max = 3,
.bs_cv_max = 15,
- .ext_info_present = 1,
+ .ext_info_present = 0,
.ext_info = {
/* The values below are just guesses ! */
.egprs_supported = 0,