diff options
author | Tobias Engel <tobias@ccc.de> | 2011-12-08 11:22:31 +0100 |
---|---|---|
committer | Tobias Engel <tobias@ccc.de> | 2011-12-08 11:22:31 +0100 |
commit | 83d61285404f85e03212d09f471020c8ca7a7fd7 (patch) | |
tree | 502f13278f2dfe98de45c5daefe171e1dde6e448 /openbsc/src/libbsc | |
parent | 11e802aba933d2f32e6b46307af486b2928537fb (diff) | |
parent | 1c5dd2c9bbc26902cdad0487e090e97e983b0787 (diff) |
Merge branch 'master' of git://git.osmocom.org/openbsc
Diffstat (limited to 'openbsc/src/libbsc')
-rw-r--r-- | openbsc/src/libbsc/Makefile.am | 1 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_nm.c | 80 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_om2000.c | 33 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_rsl.c | 189 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_api.c | 58 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_init.c | 71 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_msc.c | 4 | ||||
-rw-r--r-- | openbsc/src/libbsc/bsc_vty.c | 297 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_ericsson_rbs2000.c | 41 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_hsl_femtocell.c | 163 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_init.c | 1 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_ipaccess_nanobts.c | 200 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_nokia_site.c | 1740 | ||||
-rw-r--r-- | openbsc/src/libbsc/bts_siemens_bs11.c | 18 | ||||
-rw-r--r-- | openbsc/src/libbsc/chan_alloc.c | 4 | ||||
-rw-r--r-- | openbsc/src/libbsc/e1_config.c | 125 | ||||
-rw-r--r-- | openbsc/src/libbsc/gsm_04_08_utils.c | 4 | ||||
-rw-r--r-- | openbsc/src/libbsc/system_information.c | 4 |
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, |