diff options
Diffstat (limited to 'src/osmo-bsc/abis_rsl.c')
-rw-r--r-- | src/osmo-bsc/abis_rsl.c | 711 |
1 files changed, 530 insertions, 181 deletions
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index 402ea27bc..49e8b52c3 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -44,6 +44,7 @@ #include <osmocom/gsm/rsl.h> #include <osmocom/core/talloc.h> #include <osmocom/bsc/pcu_if.h> +#include <osmocom/bsc/pcuif_proto.h> #include <osmocom/bsc/gsm_08_08.h> #include <osmocom/netif/rtp.h> #include <osmocom/core/tdef.h> @@ -57,6 +58,8 @@ #include <osmocom/bsc/bts.h> #include <osmocom/bsc/power_control.h> #include <osmocom/bsc/chan_counts.h> +#include <osmocom/bsc/lchan.h> +#include <osmocom/bsc/vgcs_fsm.h> static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, struct gsm_meas_rep *resp) @@ -159,13 +162,13 @@ static void pad_macblock(uint8_t *out, const uint8_t *in, int len) * 'out' must provide room for 17 bytes. */ static int build_encr_info(uint8_t *out, struct gsm_lchan *lchan) { - *out++ = lchan->encr.alg_id & 0xff; - switch (lchan->encr.alg_id) { + out[0] = ALG_A5_NR_TO_RSL(lchan->encr.alg_a5_n); + switch (out[0]) { case GSM0808_ALG_ID_A5_1: case GSM0808_ALG_ID_A5_2: case GSM0808_ALG_ID_A5_3: if (!lchan->encr.key_len) { - LOG_LCHAN(lchan, LOGL_ERROR, "A5/%d encryption chosen, but missing Kc\n", lchan->encr.alg_id); + LOG_LCHAN(lchan, LOGL_ERROR, "A5/%d encryption chosen, but missing Kc\n", lchan->encr.alg_a5_n); return -EINVAL; } /* fall through */ @@ -177,7 +180,7 @@ static int build_encr_info(uint8_t *out, struct gsm_lchan *lchan) * even for A5/0. Currently our ttcn3 test suite does expect the key to be present also for A5/0, see * f_cipher_mode() in bsc/MSC_ConnectionHandler.ttcn. */ if (lchan->encr.key_len) - memcpy(out, lchan->encr.key, lchan->encr.key_len); + memcpy(&out[1], lchan->encr.key, lchan->encr.key_len); return 1 + lchan->encr.key_len; case GSM0808_ALG_ID_A5_4: @@ -185,11 +188,11 @@ static int build_encr_info(uint8_t *out, struct gsm_lchan *lchan) LOG_LCHAN(lchan, LOGL_ERROR, "A5/4 encryption chosen, but missing Kc128\n"); return -EINVAL; } - memcpy(out, lchan->encr.kc128, sizeof(lchan->encr.kc128)); + memcpy(&out[1], lchan->encr.kc128, sizeof(lchan->encr.kc128)); return 1 + sizeof(lchan->encr.kc128); default: - LOG_LCHAN(lchan, LOGL_ERROR, "A5/%d encryption not supported\n", lchan->encr.alg_id); + LOG_LCHAN(lchan, LOGL_ERROR, "A5/%d encryption not supported\n", lchan->encr.alg_a5_n); return -EINVAL; } } @@ -404,12 +407,11 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan) static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, struct gsm_lchan *lchan, const struct channel_mode_and_rate *ch_mode_rate, - bool vamos) + enum lchan_type_for type_for) { int rc; memset(cm, 0, sizeof(*cm)); - /* FIXME: what to do with data calls ? */ cm->dtx_dtu = 0; if (lchan->ts->trx->bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED) cm->dtx_dtu |= RSL_CMOD_DTXu; @@ -429,17 +431,41 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, cm->chan_rt = RSL_CMOD_CRT_SDCCH; break; case GSM_LCHAN_TCH_F: - cm->chan_rt = vamos ? RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm : RSL_CMOD_CRT_TCH_Bm; + switch (type_for) { + case LCHAN_TYPE_FOR_VAMOS: + cm->chan_rt = RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm; + break; + case LCHAN_TYPE_FOR_VGCS: + cm->chan_rt = RSL_CMOD_CRT_TCH_GROUP_Bm; + break; + case LCHAN_TYPE_FOR_VBS: + cm->chan_rt = RSL_CMOD_CRT_TCH_BCAST_Bm; + break; + default: + cm->chan_rt = RSL_CMOD_CRT_TCH_Bm; + } break; case GSM_LCHAN_TCH_H: - cm->chan_rt = vamos ? RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm : RSL_CMOD_CRT_TCH_Lm; + switch (type_for) { + case LCHAN_TYPE_FOR_VAMOS: + cm->chan_rt = RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm; + break; + case LCHAN_TYPE_FOR_VGCS: + cm->chan_rt = RSL_CMOD_CRT_TCH_GROUP_Lm; + break; + case LCHAN_TYPE_FOR_VBS: + cm->chan_rt = RSL_CMOD_CRT_TCH_BCAST_Lm; + break; + default: + cm->chan_rt = RSL_CMOD_CRT_TCH_Lm; + } break; case GSM_LCHAN_NONE: case GSM_LCHAN_UNKNOWN: default: LOGP(DRSL, LOGL_ERROR, "unsupported activation lchan->type %u %s\n", - lchan->type, gsm_lchant_name(lchan->type)); + lchan->type, gsm_chan_t_name(lchan->type)); return -EINVAL; } @@ -459,54 +485,13 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, case GSM48_CMODE_DATA_14k5: case GSM48_CMODE_DATA_12k0: case GSM48_CMODE_DATA_6k0: - switch (ch_mode_rate->csd_mode) { - case LCHAN_CSD_M_NT: - /* non-transparent CSD with RLP */ - switch (ch_mode_rate->chan_mode) { - case GSM48_CMODE_DATA_14k5: - cm->chan_rate = RSL_CMOD_SP_NT_14k5; - break; - case GSM48_CMODE_DATA_12k0: - cm->chan_rate = RSL_CMOD_SP_NT_12k0; - break; - case GSM48_CMODE_DATA_6k0: - cm->chan_rate = RSL_CMOD_SP_NT_6k0; - break; - default: - LOGP(DRSL, LOGL_ERROR, - "unsupported lchan->tch_mode %u\n", - ch_mode_rate->chan_mode); - return -EINVAL; - } - break; - /* transparent data services below */ - case LCHAN_CSD_M_T_1200_75: - cm->chan_rate = RSL_CMOD_CSD_T_1200_75; - break; - case LCHAN_CSD_M_T_600: - cm->chan_rate = RSL_CMOD_CSD_T_600; - break; - case LCHAN_CSD_M_T_1200: - cm->chan_rate = RSL_CMOD_CSD_T_1200; - break; - case LCHAN_CSD_M_T_2400: - cm->chan_rate = RSL_CMOD_CSD_T_2400; - break; - case LCHAN_CSD_M_T_9600: - cm->chan_rate = RSL_CMOD_CSD_T_9600; - break; - case LCHAN_CSD_M_T_14400: - cm->chan_rate = RSL_CMOD_CSD_T_14400; - break; - case LCHAN_CSD_M_T_29000: - cm->chan_rate = RSL_CMOD_CSD_T_29000; - break; - case LCHAN_CSD_M_T_32000: - cm->chan_rate = RSL_CMOD_CSD_T_32000; - break; - default: - LOGP(DRSL, LOGL_ERROR, "unsupported csd_mode %u\n", ch_mode_rate->csd_mode); - return -EINVAL; + case GSM48_CMODE_DATA_3k6: + /* 3GPP TS 48.058 ยง 9.3.6 Channel Mode octet 6 */ + if (ch_mode_rate->data_transparent) { + cm->chan_rate = ch_mode_rate->data_rate.t; + } else { + cm->chan_rate = ch_mode_rate->data_rate.nt; + cm->chan_rate |= 0x40; } break; default: @@ -615,7 +600,7 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref) /* PDCH activation is a job for rsl_tx_dyn_ts_pdch_act_deact(); */ OSMO_ASSERT(act_type != RSL_ACT_OSMO_PDCH); - rc = channel_mode_from_lchan(&cm, lchan, &lchan->activate.ch_mode_rate, lchan->activate.info.vamos); + rc = channel_mode_from_lchan(&cm, lchan, &lchan->activate.ch_mode_rate, lchan->activate.info.type_for); if (rc < 0) { LOGP(DRSL, LOGL_ERROR, "%s Cannot find channel mode from lchan type\n", @@ -660,7 +645,7 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref) msg->l3h = len + 1; *len = msgb_l3len(msg); - if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) { + if (lchan->encr.alg_a5_n > 0) { uint8_t encr_info[MAX_A5_KEY_LEN+2]; rc = build_encr_info(encr_info, lchan); if (rc > 0) @@ -717,7 +702,7 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref) put_top_acch_cap_ie(lchan, &cm, msg); /* Selecting a specific TSC Set is only applicable to VAMOS mode */ - if (lchan->activate.info.vamos && lchan->activate.tsc_set >= 1) + if (lchan->activate.info.type_for == LCHAN_TYPE_FOR_VAMOS && lchan->activate.tsc_set >= 1) put_osmo_training_sequence_ie(msg, lchan->activate.tsc_set, lchan->activate.tsc); msg->dst = rsl_chan_link(lchan); @@ -752,7 +737,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) if (chan_nr < 0) return chan_nr; - rc = channel_mode_from_lchan(&cm, lchan, &lchan->modify.ch_mode_rate, lchan->modify.info.vamos); + rc = channel_mode_from_lchan(&cm, lchan, &lchan->modify.ch_mode_rate, lchan->modify.info.type_for); if (rc < 0) return rc; @@ -764,7 +749,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), (uint8_t *) &cm); - if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) { + if (lchan->encr.alg_a5_n > 0) { uint8_t encr_info[MAX_A5_KEY_LEN+2]; rc = build_encr_info(encr_info, lchan); if (rc > 0) @@ -790,7 +775,8 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) /* Selecting a specific TSC Set is only applicable to VAMOS mode. Send this Osmocom specific IE only to OsmoBTS * types. */ - if (lchan->modify.info.vamos && lchan->modify.tsc_set >= 1 && bts->model->type == GSM_BTS_TYPE_OSMOBTS) + if (lchan->modify.info.type_for == LCHAN_TYPE_FOR_VAMOS && lchan->modify.tsc_set >= 1 && + bts->model->type == GSM_BTS_TYPE_OSMOBTS) put_osmo_training_sequence_ie(msg, lchan->modify.tsc_set, lchan->modify.tsc); msg->dst = rsl_chan_link(lchan); @@ -880,14 +866,14 @@ int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, const struct osmo_mobile_identity *mi, uint8_t chan_needed, bool is_gprs) { - struct abis_rsl_dchan_hdr *dh; + struct abis_rsl_cchan_hdr *cch; struct msgb *msg = rsl_msgb_alloc(); uint8_t *l; int rc; - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_PAGING_CMD); - dh->chan_nr = RSL_CHAN_PCH_AGCH; + cch = (struct abis_rsl_cchan_hdr *) msgb_put(msg, sizeof(*cch)); + rsl_init_cchan_hdr(cch, RSL_MT_PAGING_CMD); + cch->chan_nr = RSL_CHAN_PCH_AGCH; msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group); @@ -911,6 +897,45 @@ int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, return abis_rsl_sendmsg(msg); } +/* Chapter 8.5.10: NOTIFICATION COMMAND */ +int rsl_notification_cmd(struct gsm_bts *bts, struct gsm_lchan *lchan, struct gsm0808_group_callref *gc, uint8_t *drx) +{ + struct abis_rsl_cchan_hdr *cch; + struct msgb *msg = rsl_msgb_alloc(); + struct gsm48_chan_desc cd; + uint8_t sti = (lchan) ? RSL_CMD_INDICATOR_START : RSL_CMD_INDICATOR_STOP; + uint8_t *t; + int rc; + + cch = (struct abis_rsl_cchan_hdr *) msgb_put(msg, sizeof(*cch)); + rsl_init_cchan_hdr(cch, RSL_MT_NOT_CMD); + cch->chan_nr = RSL_CHAN_PCH_AGCH; + + msgb_tlv_put(msg, RSL_IE_CMD_INDICATOR, 1, &sti); + + /* Use TLV encoding from TS 08.08. Change different IE type. */ + t = msg->tail; + gsm0808_enc_group_callref(msg, gc); + *t = RSL_IE_GROUP_CALL_REF; + + if (lchan) { + memset(&cd, 0, sizeof(cd)); + rc = gsm48_lchan2chan_desc(&cd, lchan, lchan->activate.tsc, true); + if (rc) { + LOG_LCHAN(lchan, LOGL_ERROR, "Error encoding Channel Number\n"); + msgb_free(msg); + return rc; + } + msgb_tlv_put(msg, RSL_IE_CHAN_DESC, sizeof(cd), (const uint8_t *)&cd); + + if (drx) + msgb_tlv_put(msg, RSL_IE_NCH_DRX_INFO, 1, drx); + } + + msg->dst = bts->c0->rsl_link_primary; + return abis_rsl_sendmsg(msg); +} + int rsl_forward_layer3_info(struct gsm_lchan *lchan, const uint8_t *l3_info, uint8_t l3_info_len) { struct msgb *msg; @@ -926,30 +951,21 @@ int rsl_forward_layer3_info(struct gsm_lchan *lchan, const uint8_t *l3_info, uin return rsl_data_request(msg, 0); } -int imsi_str2bcd(uint8_t *bcd_out, const char *str_in) -{ - int i, len = strlen(str_in); - - for (i = 0; i < len; i++) { - int num = str_in[i] - 0x30; - if (num < 0 || num > 9) - return -1; - if (i % 2 == 0) - bcd_out[i/2] = num; - else - bcd_out[i/2] |= (num << 4); - } - - return 0; -} - /* Chapter 8.5.6 */ -struct msgb *rsl_imm_assign_cmd_common(struct gsm_bts *bts, uint8_t len, uint8_t *val) +struct msgb *rsl_imm_assign_cmd_common(const struct gsm_bts *bts, uint8_t len, const uint8_t *val) { - struct msgb *msg = rsl_msgb_alloc(); + struct msgb *msg; struct abis_rsl_dchan_hdr *dh; uint8_t buf[GSM_MACBLOCK_LEN]; + if (len > sizeof(buf)) { + LOGP(DRSL, LOGL_ERROR, + "Cannot send IMMEDIATE ASSIGNMENT message with excessive length (%u)\n", len); + return NULL; + } + + msg = rsl_msgb_alloc(); + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD); dh->chan_nr = RSL_CHAN_PCH_AGCH; @@ -971,7 +987,7 @@ struct msgb *rsl_imm_assign_cmd_common(struct gsm_bts *bts, uint8_t len, uint8_t } /* Chapter 8.5.6 */ -int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val) +int rsl_imm_assign_cmd(const struct gsm_bts *bts, uint8_t len, const uint8_t *val) { struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val); if (!msg) @@ -979,17 +995,24 @@ int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val) return abis_rsl_sendmsg(msg); } -/* Chapter 8.5.6 */ -int rsl_ericsson_imm_assign_cmd(struct gsm_bts *bts, uint32_t tlli, uint8_t len, uint8_t *val) +/* Chapter 8.5.6 Immediate Assignment Command (with Ericcson vendor specific RSL extension) */ +int rsl_ericsson_imm_assign_cmd(const struct gsm_bts *bts, uint32_t msg_id, uint8_t len, + const uint8_t *val, uint8_t pag_grp, bool confirm) { struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val); if (!msg) return 1; + /* Append ericsson proprietary paging group IE, this will instruct the BTS to + * send this immediate assignment through PCH instead of AGCH. */ + msgb_tv_put(msg, RSL_IE_ERIC_PAGING_GROUP, pag_grp); + /* ericsson can handle a reference at the end of the message which is used in * the confirm message. The confirm message is only sent if the trailer is present */ - msgb_put_u8(msg, RSL_IE_ERIC_MOBILE_ID); - msgb_put_u32(msg, tlli); + if (confirm) { + msgb_put_u8(msg, RSL_IE_ERIC_MOBILE_ID); + msgb_put_u32(msg, msg_id); + } return abis_rsl_sendmsg(msg); } @@ -1148,6 +1171,31 @@ int rsl_data_request(struct msgb *msg, uint8_t link_id) return abis_rsl_sendmsg(msg); } +/* Send "UNIT DATA REQUEST" message with given L3 Info payload */ +/* Chapter 8.3.11 */ +int rsl_unit_data_request(struct msgb *msg, uint8_t link_id) +{ + int chan_nr; + + if (msg->lchan == NULL) { + LOGP(DRSL, LOGL_ERROR, "cannot send UNIT DATA REQUEST to unknown lchan\n"); + msgb_free(msg); + return -EINVAL; + } + + chan_nr = gsm_lchan2chan_nr(msg->lchan, true); + if (chan_nr < 0) { + msgb_free(msg); + return chan_nr; + } + + rsl_rll_push_l3(msg, RSL_MT_UNIT_DATA_REQ, chan_nr, link_id, 1); + + msg->dst = rsl_chan_link(msg->lchan); + + return abis_rsl_sendmsg(msg); +} + /* Send "ESTABLISH REQUEST" message with given L3 Info payload */ /* Chapter 8.3.1 */ int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id) @@ -1221,7 +1269,12 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) return -EINVAL; } - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + cause_p = rsl_cause(&tp); LOG_LCHAN(lchan, LOGL_ERROR, "CHANNEL ACTIVATE NACK%s\n", rsl_cause_name(&tp)); @@ -1241,7 +1294,12 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct tlv_parsed tp; const uint8_t *cause_p; - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + cause_p = rsl_cause(&tp); LOG_LCHAN(lchan, LOGL_ERROR, "CONNECTION FAIL%s\n", rsl_cause_name(&tp)); @@ -1259,6 +1317,15 @@ static int rsl_rx_conn_fail(struct msgb *msg) break; } + /* Report to VGCS FSM */ + if (lchan_is_asci(lchan)) { + if (lchan->conn && lchan->conn->vgcs_chan.fi) { + uint8_t cause = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE; + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_FAIL, &cause); + } + return 0; + } + /* If the lchan is associated with a conn, we shall notify the MSC of the RSL Conn Failure, and * the connection will presumably be torn down and lead to an lchan release. During initial * Channel Request from the MS, an lchan has no conn yet, so in that case release now. */ @@ -1385,7 +1452,11 @@ static int rsl_rx_meas_res(struct msgb *msg) memset(mr, 0, sizeof(*mr)); mr->lchan = msg->lchan; - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || !TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS) || @@ -1466,7 +1537,11 @@ static int rsl_rx_hando_det(struct msgb *msg) .msg = msg, }; - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) d.access_delay = TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY); @@ -1482,6 +1557,66 @@ static int rsl_rx_hando_det(struct msgb *msg) return 0; } +/* Chapter 8.4.21: TALKER DETECTION */ +static int rsl_rx_talker_det(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tp; + /* We use this struct, because it has same data. */ + struct handover_rr_detect_data d = { + .msg = msg, + }; + + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + + if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) + d.access_delay = TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY); + + if (!msg->lchan->conn || !msg->lchan->conn->vgcs_chan.fi) { + LOGP(DRSL, LOGL_ERROR, "%s TALKER DETECTION but no VGCS channel\n", + gsm_lchan_name(msg->lchan)); + return 0; + } + + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_DET, &d); + + return 0; +} + +/* Chapter 8.4.22: LISTENER DETECTION */ +static int rsl_rx_listener_det(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tp; + /* We use this struct, because it has same data. */ + struct handover_rr_detect_data d = { + .msg = msg, + }; + + if (rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + + if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) + d.access_delay = TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY); + + if (!msg->lchan->conn || !msg->lchan->conn->vgcs_chan.fi) { + LOGP(DRSL, LOGL_ERROR, "%s LISTENER DETECTION but no VGCS channel\n", + gsm_lchan_name(msg->lchan)); + return 0; + } + + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_LISTENER_DET, &d); + + return 0; +} + static int rsl_rx_ipacc_pdch(struct msgb *msg, char *name, uint32_t ts_ev) { struct gsm_bts_trx_ts *ts = msg->lchan->ts; @@ -1502,6 +1637,9 @@ static int abis_rsl_rx_dchan(struct msgb *msg) int rc = 0; struct e1inp_sign_link *sign_link = msg->dst; + if (msgb_l2len(msg) < sizeof(*rslh)) + return -EINVAL; + if (rslh->ie_chan != RSL_IE_CHAN_NR) { LOGP(DRSL, LOGL_ERROR, "Rx RSL DCHAN: invalid RSL header, expecting Channel Number IE tag, got 0x%x\n", @@ -1527,6 +1665,10 @@ static int abis_rsl_rx_dchan(struct msgb *msg) switch (rslh->c.msg_type) { case RSL_MT_CHAN_ACTIV_ACK: + /* Ignore acknowlegement of channel reactivation, if a VGCS/VBS channel was reactivated to assign + * the calling subscriber to it. */ + if (msg->lchan->conn && msg->lchan->conn->assignment.req.vgcs) + break; if (msg_for_osmocom_dyn_ts(msg)) osmo_fsm_inst_dispatch(msg->lchan->ts->fi, TS_EV_PDCH_ACT_ACK, NULL); else { @@ -1546,6 +1688,12 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_HANDO_DET: rc = rsl_rx_hando_det(msg); break; + case RSL_MT_TALKER_DET: + rc = rsl_rx_talker_det(msg); + break; + case RSL_MT_LISTENER_DET: + rc = rsl_rx_listener_det(msg); + break; case RSL_MT_RF_CHAN_REL_ACK: if (msg_for_osmocom_dyn_ts(msg)) osmo_fsm_inst_dispatch(msg->lchan->ts->fi, TS_EV_PDCH_DEACT_ACK, NULL); @@ -1576,8 +1724,6 @@ static int abis_rsl_rx_dchan(struct msgb *msg) break; case RSL_MT_PHY_CONTEXT_CONF: case RSL_MT_PREPROC_MEAS_RES: - case RSL_MT_TALKER_DET: - case RSL_MT_LISTENER_DET: case RSL_MT_REMOTE_CODEC_CONF_REP: case RSL_MT_MR_CODEC_MOD_ACK: case RSL_MT_MR_CODEC_MOD_NACK: @@ -1602,7 +1748,14 @@ static int rsl_rx_error_rep(struct msgb *msg) struct tlv_parsed tp; struct e1inp_sign_link *sign_link = msg->dst; - rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); + if (msgb_l2len(msg) < sizeof(*rslh)) + return -EINVAL; + + if (rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg) - sizeof(*rslh)) < 0) { + LOGP(DRSL, LOGL_ERROR, "%s Failed to parse RSL %s\n", + gsm_trx_name(sign_link->trx), rsl_or_ipac_msg_name(rslh->msg_type)); + return -EINVAL; + } LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT%s\n", gsm_trx_name(sign_link->trx), rsl_cause_name(&tp)); @@ -1619,7 +1772,7 @@ static int rsl_rx_resource_indication(struct msgb *msg) struct gsm_bts_trx *trx = sign_link->trx; struct gsm_lchan *lchan; int ts_nr; - int rc, i; + int i; LOGP(DRSL, LOGL_DEBUG, "%s Rx Resource Indication\n", gsm_trx_name(trx)); @@ -1633,9 +1786,9 @@ static int rsl_rx_resource_indication(struct msgb *msg) } } - rc = rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg) - sizeof(*rslh)); - if (rc < 0) { - LOGP(DRSL, LOGL_ERROR, "Rx Resource Indication: failed to parse the message\n"); + if (rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg) - sizeof(*rslh)) < 0) { + LOGP(DRSL, LOGL_ERROR, "%s Failed to parse RSL %s\n", + gsm_trx_name(trx), rsl_or_ipac_msg_name(rslh->msg_type)); return -EINVAL; } @@ -1788,25 +1941,29 @@ struct chan_rqd { /* Handle packet channel rach requests */ static int rsl_rx_pchan_rqd(struct chan_rqd *rqd) { - uint8_t t1, t2, t3; uint32_t fn; uint8_t rqd_ta; uint8_t is_11bit; + struct gsm_time gsm_time; /* Process rach request and forward contained information to PCU */ if (rqd->ref.ra == 0x7F) { is_11bit = 1; /* FIXME: Also handle 11 bit rach requests */ - LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n",rqd->bts->nr); + LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n", rqd->bts->nr); return -EINVAL; } else { is_11bit = 0; - t1 = rqd->ref.t1; - t2 = rqd->ref.t2; - t3 = rqd->ref.t3_low | (rqd->ref.t3_high << 3); - fn = (51 * ((t3-t2) % 26) + t3 + 51 * 26 * t1); rqd_ta = rqd->ta; + + gsm_time.t1 = rqd->ref.t1; + gsm_time.t2 = rqd->ref.t2; + gsm_time.t3 = rqd->ref.t3_low | (rqd->ref.t3_high << 3); + fn = gsm_gsmtime2fn(&gsm_time); + + LOG_BTS(rqd->bts, DRSL, LOGL_INFO, "CHAN RQD: fn(t1=%u,t3=%u,t2=%u) = %u\n", + gsm_time.t1, gsm_time.t3, gsm_time.t2, fn); } return pcu_tx_rach_ind(rqd->bts, rqd_ta, rqd->ref.ra, fn, is_11bit, @@ -1818,7 +1975,6 @@ static int rsl_rx_pchan_rqd(struct chan_rqd *rqd) * requests from the queue to prevent the queue from growing indefinetly. */ static void reduce_rach_dos(struct gsm_bts *bts) { - int rlt = gsm_bts_get_radio_link_timeout(bts); time_t timestamp_current = time(NULL); struct chan_rqd *rqd; struct chan_rqd *rqd_tmp; @@ -1826,9 +1982,9 @@ static void reduce_rach_dos(struct gsm_bts *bts) /* Drop all expired channel requests in the list */ llist_for_each_entry_safe(rqd, rqd_tmp, &bts->chan_rqd_queue, entry) { - /* If the channel request is older than the radio link timeout we drop it. This also means that the + /* If the channel request is older than the rach expiry timeout we drop it. This also means that the * queue is under its overflow limit again. */ - if (timestamp_current - rqd->timestamp > rlt) { + if (timestamp_current - rqd->timestamp > bts->rach_expiry_timeout) { LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: tossing expired channel request" "(ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n", rqd->ref.ra, bts->network->neci, rqd->reason); @@ -1900,8 +2056,10 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* Determine channel request cause code */ rqd->reason = get_reason_by_chreq(rqd->ref.ra, bts->network->neci); - LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n", - get_value_string(gsm_chreq_descs, rqd->reason), rqd->ref.ra, bts->network->neci, rqd->reason); + LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: reason: %s (ra=0x%02x, t1=%d, t3=%d, t2=%d, neci=0x%02x, chreq_reason=0x%02x)\n", + get_value_string(gsm_chreq_descs, rqd->reason), rqd->ref.ra, + rqd->ref.t1, rqd->ref.t3_high << 3 | rqd->ref.t3_low, rqd->ref.t2, + bts->network->neci, rqd->reason); rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_TOTAL)); switch (rqd->reason) { @@ -1932,7 +2090,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) if (rqd->reason == GSM_CHREQ_REASON_EMERG) { if (bts->si_common.rach_control.t2 & 0x4) { LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: MS attempts EMERGENCY CALL although EMERGENCY CALLS " - "are not allowed in sysinfo (spec violation by MS!)\n"); + "are not allowed in sysinfo (cfg: network / bts / rach emergency call allowed 0)\n"); rsl_tx_imm_ass_rej(bts, &rqd->ref); talloc_free(rqd); return 0; @@ -1967,10 +2125,10 @@ static struct gsm_lchan *get_any_lchan(struct gsm_bts *bts) ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) { if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H) { if (lchan->fi->state == LCHAN_ST_ESTABLISHED) { - if (!lchan_est || bts->chan_alloc_reverse) + if (!lchan_est || bts->chan_alloc_chan_req_reverse) lchan_est = lchan; } else { - if (!lchan_any || bts->chan_alloc_reverse) + if (!lchan_any || bts->chan_alloc_chan_req_reverse) lchan_any = lchan; } } @@ -1996,23 +2154,23 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd) /* First check the situation on the BTS, if we have TCH/H or TCH/F resources available for another (EMERGENCY) * call. If yes, then no (further) action has to be carried out. */ - if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, true)) { + if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, SELECT_FOR_MS_CHAN_REQ, NULL, true)) { LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE, "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/F is (now) available!\n"); return false; } - if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, true)) { + if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, SELECT_FOR_MS_CHAN_REQ, NULL, true)) { LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE, "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/H is (now) available!\n"); return false; } - /* No free TCH/F or TCH/H was found, we now select one of the busy lchans and initate a release on that lchan. - * This will take a short amount of time. We need to come back and check regulary to see if we managed to + /* No free TCH/F or TCH/H was found, we now select one of the busy lchans and initiate a release on that lchan. + * This will take a short amount of time. We need to come back and check regularly to see if we managed to * free up another lchan. */ if (!rqd->release_lchan) { struct gsm_lchan *release_lchan; - /* Pick any busy TCH/F or TCH/H lchan and inititate a channel + /* Pick any busy TCH/F or TCH/H lchan and initiate a channel * release to make room for the incoming emergency call */ rqd->release_lchan = release_lchan = get_any_lchan(rqd->bts); if (!release_lchan) { @@ -2030,16 +2188,21 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd) "CHAN RQD/EMERGENCY-PRIORITY: inducing termination of lchan %s (state:%s) in favor of incoming EMERGENCY CALL!\n", gsm_lchan_name(release_lchan), osmo_fsm_inst_state_name(release_lchan->fi)); - lchan_release(release_lchan, !!(release_lchan->conn), true, 0, + /* Make sure the Clear Request to the MSC has the proper cause */ + if (release_lchan->conn) + gscon_bssmap_clear(release_lchan->conn, GSM0808_CAUSE_PREEMPTION); + /* The gscon FSM would only release the lchan after the MSC responds with a Clear Command. + * But we need it released right now. Also with the right RR cause. */ + lchan_release(release_lchan, !!(release_lchan->conn), true, GSM48_RR_CAUSE_PREMPTIVE_REL, gscon_last_eutran_plmn(release_lchan->conn)); /* Also release any overlapping VAMOS multiplexes on this lchan */ release_lchan = gsm_lchan_primary_to_vamos(release_lchan); if (release_lchan) - lchan_release(release_lchan, !!(release_lchan->conn), true, 0, + lchan_release(release_lchan, !!(release_lchan->conn), true, GSM48_RR_CAUSE_PREMPTIVE_REL, gscon_last_eutran_plmn(release_lchan->conn)); } else { - /* BTS is shutting down, give up... */ + /* if BTS has shut down, give up... */ if (rqd->release_lchan->ts->fi->state == TS_ST_NOT_INITIALIZED) return false; @@ -2063,25 +2226,23 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd) struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_rqd *rqd, enum gsm_chan_t lctype) { - struct chan_counts bts_counts; struct gsm_lchan *lchan = NULL; int free_tchf, free_tchh; bool needs_dyn_switch; - lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, false); + lchan = lchan_avail_by_type(bts, GSM_LCHAN_SDCCH, SELECT_FOR_MS_CHAN_REQ, NULL, false); if (!lchan) return NULL; needs_dyn_switch = lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN && lchan->ts->pchan_is != GSM_PCHAN_SDCCH8_SACCH8C; - chan_counts_for_bts(&bts_counts, bts); - free_tchf = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]; - free_tchh = bts_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]; + free_tchf = bts->chan_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F]; + free_tchh = bts->chan_counts.val[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H]; if (free_tchf == 0 && free_tchh == 0) { LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: 0x%x Requesting %s reason=call but no TCH available\n", - rqd->ref.ra, gsm_lchant_name(lctype)); + rqd->ref.ra, gsm_chan_t_name(lctype)); return NULL; } @@ -2110,7 +2271,7 @@ struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_ LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: 0x%x Requesting %s reason=call but dyn TS switch to " "SDCCH would starve the single available TCH timeslot\n", - rqd->ref.ra, gsm_lchant_name(lctype)); + rqd->ref.ra, gsm_chan_t_name(lctype)); return NULL; } @@ -2132,8 +2293,8 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) /* Handle PDCH related rach requests (in case of BSC-co-located-PCU) */ if (rqd->reason == GSM_CHREQ_REASON_PDCH) { - rsl_rx_pchan_rqd(rqd); - return; + if (rsl_rx_pchan_rqd(rqd) == 0) + goto leave; } /* Ensure that emergency calls will get priority over regular calls, however releasing @@ -2158,29 +2319,39 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) if (rqd->reason == GSM_CHREQ_REASON_CALL) { lchan = _select_sdcch_for_call(bts, rqd, lctype); } else if (rqd->reason != GSM_CHREQ_REASON_EMERG) { - lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH); + lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH, + SELECT_FOR_MS_CHAN_REQ, + NULL); } /* else: Emergency calls will be put on a free TCH/H or TCH/F directly * in the code below, all other channel requests will get an SDCCH first * (if possible). */ - if (gsm_chreq_reason_is_voicecall(rqd->reason) || bts->chan_alloc_allow_tch_for_signalling) { + if (bts->chan_alloc_tch_signalling_policy == BTS_TCH_SIGNALLING_ALWAYS || + (bts->chan_alloc_tch_signalling_policy == BTS_TCH_SIGNALLING_VOICE && + gsm_chreq_reason_is_voicecall(rqd->reason)) || + (bts->chan_alloc_tch_signalling_policy == BTS_TCH_SIGNALLING_EMERG && + rqd->reason == GSM_CHREQ_REASON_EMERG)) { if (!lchan) { LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD[%s]: no resources for %s 0x%x, retrying with %s\n", - get_value_string(gsm_chreq_descs, rqd->reason), gsm_lchant_name(GSM_LCHAN_SDCCH), - rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_H)); - lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H); + get_value_string(gsm_chreq_descs, rqd->reason), gsm_chan_t_name(GSM_LCHAN_SDCCH), + rqd->ref.ra, gsm_chan_t_name(GSM_LCHAN_TCH_H)); + lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H, + SELECT_FOR_MS_CHAN_REQ, + NULL); } if (!lchan) { LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD[%s]: no resources for %s 0x%x, retrying with %s\n", - get_value_string(gsm_chreq_descs, rqd->reason), gsm_lchant_name(GSM_LCHAN_SDCCH), - rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_F)); - lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F); + get_value_string(gsm_chreq_descs, rqd->reason), gsm_chan_t_name(GSM_LCHAN_SDCCH), + rqd->ref.ra, gsm_chan_t_name(GSM_LCHAN_TCH_F)); + lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F, + SELECT_FOR_MS_CHAN_REQ, + NULL); } } if (!lchan) { LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD[%s]: no resources for %s 0x%x\n", - get_value_string(gsm_chreq_descs, rqd->reason), gsm_lchant_name(lctype), rqd->ref.ra); + get_value_string(gsm_chreq_descs, rqd->reason), gsm_chan_t_name(lctype), rqd->ref.ra); rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_CHREQ_NO_CHANNEL)); rsl_tx_imm_ass_rej(bts, &rqd->ref); llist_del(&rqd->entry); @@ -2209,6 +2380,8 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) }; lchan_activate(lchan, &info); + +leave: llist_del(&rqd->entry); talloc_free(rqd); return; @@ -2292,7 +2465,7 @@ int rsl_tx_imm_assignment(struct gsm_lchan *lchan) return rc; } -/* current load on the CCCH */ +/* 5.4 and 8.5.2 Rx CCCH Load Ind */ static int rsl_rx_ccch_load(struct msgb *msg) { struct e1inp_sign_link *sign_link = msg->dst; @@ -2300,18 +2473,16 @@ static int rsl_rx_ccch_load(struct msgb *msg) struct ccch_signal_data sd; sd.bts = sign_link->trx->bts; - sd.rach_slot_count = -1; - sd.rach_busy_count = -1; - sd.rach_access_count = -1; + sd.rach_slot_count = UINT16_MAX; + sd.rach_busy_count = UINT16_MAX; + sd.rach_access_count = UINT16_MAX; switch (rslh->data[0]) { case RSL_IE_PAGING_LOAD: sd.pg_buf_space = rslh->data[1] << 8 | rslh->data[2]; - if (is_ipaccess_bts(sign_link->trx->bts) && sd.pg_buf_space == 0xffff) { - /* paging load below configured threshold, use 50 as default */ - sd.pg_buf_space = 50; + if (is_ipa_abisip_bts(sd.bts) && sd.pg_buf_space == UINT16_MAX) { + sd.pg_buf_space = paging_estimate_available_slots(sd.bts, sd.bts->ccch_load_ind_period); } - paging_update_buffer_space(sign_link->trx->bts, sd.pg_buf_space); osmo_signal_dispatch(SS_CCCH, S_CCCH_PAGING_LOAD, &sd); break; case RSL_IE_RACH_LOAD: @@ -2355,7 +2526,12 @@ static int rsl_rx_cbch_load(struct msgb *msg) struct tlv_parsed tp; uint8_t slot_count; - rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg) - sizeof(*rslh)); + if (rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg) - sizeof(*rslh)) < 0) { + LOGP(DRSL, LOGL_ERROR, "%s Failed to parse RSL %s\n", + gsm_trx_name(sign_link->trx), rsl_or_ipac_msg_name(rslh->c.msg_type)); + return -EINVAL; + } + if (!TLVP_PRESENT(&tp, RSL_IE_CBCH_LOAD_INFO)) { LOG_BTS(bts, DRSL, LOGL_ERROR, "CBCH LOAD IND without mandatory CBCH Load Info IE\n"); return -1; @@ -2378,7 +2554,7 @@ static int rsl_rx_ericsson_imm_assign_sent(struct msgb *msg) { struct e1inp_sign_link *sign_link = msg->dst; struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - uint32_t tlli; + uint32_t msg_id; LOGP(DRSL, LOGL_INFO, "IMM.ass sent\n"); msgb_pull(msg, sizeof(*dh)); @@ -2390,8 +2566,8 @@ static int rsl_rx_ericsson_imm_assign_sent(struct msgb *msg) LOGP(DRSL, LOGL_ERROR, "unsupported IMM.ass message format! (please fix)\n"); else { msgb_pull(msg, 1); /* drop previous data to use msg_pull_u32 */ - tlli = msgb_pull_u32(msg); - pcu_tx_imm_ass_sent(sign_link->trx->bts, tlli); + msg_id = msgb_pull_u32(msg); + pcu_tx_data_cnf(sign_link->trx->bts, msg_id, PCU_IF_SAPI_PCH_2); } return 0; } @@ -2403,6 +2579,9 @@ static int abis_rsl_rx_cchan(struct msgb *msg) struct rate_ctr_group *bts_ctrs = sign_link->trx->bts->bts_ctrs; int rc = 0; + if (msgb_l2len(msg) < sizeof(*rslh)) + return -EINVAL; + msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr, "Abis RSL rx CCHAN: "); @@ -2443,9 +2622,14 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); uint8_t rlm_cause; - rsl_tlv_parse(&tp, rllh->data, msgb_l2len(msg) - sizeof(*rllh)); + if (rsl_tlv_parse(&tp, rllh->data, msgb_l2len(msg) - sizeof(*rllh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(rllh->c.msg_type)); + return -EINVAL; + } + if (!TLVP_PRESENT(&tp, RSL_IE_RLM_CAUSE)) { - LOG_LCHAN(msg->lchan, LOGL_ERROR, "ERROR INDICATION without mandantory cause.\n"); + LOG_LCHAN(msg->lchan, LOGL_ERROR, "ERROR INDICATION without mandatory cause.\n"); return -1; } @@ -2458,6 +2642,13 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RLL_ERR_IND, &rlm_cause); + /* Report to VGCS FSM */ + if (lchan_is_asci(msg->lchan)) { + if (msg->lchan->conn && msg->lchan->conn->vgcs_chan.fi) { + uint8_t cause = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE; + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_FAIL, &cause); + } + } return 0; } @@ -2472,17 +2663,30 @@ 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; - uint8_t sapi = rllh->link_id & 0x7; + uint8_t sapi; + + if (msgb_l2len(msg) < sizeof(*rllh)) + return -1; + sapi = rllh->link_id & 0x7; msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, "Abis RSL rx RLL: "); + if (OSMO_UNLIKELY(msg->lchan == NULL)) + return -1; switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: LOG_LCHAN(msg->lchan, LOGL_DEBUG, "SAPI=%u DATA INDICATION\n", sapi); - if (msgb_l2len(msg) > - sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && + + if (msgb_l2len(msg) > (sizeof(*rllh) + 3) && rllh->data[0] == RSL_IE_L3_INFO) { msg->l3h = &rllh->data[3]; + /* Data message on a VGCS channel is handled by VGCS FSM only. */ + if (lchan_is_asci(msg->lchan)) { + if (msg->lchan->conn && msg->lchan->conn->vgcs_chan.fi) + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_DATA, + msg); + return 0; + } return gsm0408_rcvmsg(msg, rllh->link_id); } break; @@ -2522,8 +2726,14 @@ static int abis_rsl_rx_rll(struct msgb *msg) msg->lchan->sapis[sapi] = LCHAN_SAPI_MS; osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RLL_ESTABLISH_IND, msg); - if (msgb_l2len(msg) > - sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && + /* Establishment message on a VGCS channel is handled by VGCS FSM only. */ + if (lchan_is_asci(msg->lchan)) { + if (msg->lchan->conn && msg->lchan->conn->vgcs_chan.fi) + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_EST, msg); + break; + } + + if (msgb_l2len(msg) > (sizeof(*rllh) + 3) && rllh->data[0] == RSL_IE_L3_INFO) { msg->l3h = &rllh->data[3]; return gsm0408_rcvmsg(msg, rllh->link_id); @@ -2538,6 +2748,14 @@ static int abis_rsl_rx_rll(struct msgb *msg) case RSL_MT_REL_IND: /* BTS informs us of having received DISC from MS */ osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RLL_REL_IND, &rllh->link_id); + + /* Report to VGCS FSM */ + if (lchan_is_asci(msg->lchan)) { + if (msg->lchan->conn && msg->lchan->conn->vgcs_chan.fi) { + uint8_t cause = GSM0808_CAUSE_CALL_CONTROL; + osmo_fsm_inst_dispatch(msg->lchan->conn->vgcs_chan.fi, VGCS_EV_TALKER_REL, &cause); + } + } break; case RSL_MT_REL_CONF: /* BTS informs us of having received UA from MS, @@ -2560,6 +2778,68 @@ static int abis_rsl_rx_rll(struct msgb *msg) return rc; } +/* Return an ip.access RTP CSD FMT value (uint8_t) or negative on error. */ +int ipacc_rtp_csd_fmt_transp(const struct channel_mode_and_rate *ch_mode_rate, + const enum rsl_ipac_rtp_csd_format_d format_d) +{ + uint8_t ret = format_d; + + switch (ch_mode_rate->data_rate.t) { + case RSL_CMOD_CSD_T_32k0: + case RSL_CMOD_CSD_T_29k0: + ret |= RSL_IPAC_RTP_CSD_IR_32k << 4; + break; + case RSL_CMOD_CSD_T_14k4: + case RSL_CMOD_CSD_T_9k6: + ret |= RSL_IPAC_RTP_CSD_IR_16k << 4; + break; + case RSL_CMOD_CSD_T_4k8: + case RSL_CMOD_CSD_T_2k4: + case RSL_CMOD_CSD_T_1k2: + case RSL_CMOD_CSD_T_600: + case RSL_CMOD_CSD_T_1200_75: + ret |= RSL_IPAC_RTP_CSD_IR_8k << 4; + break; + default: + return -EINVAL; + } + + return ret; +} + +/* Return an ip.access RTP CSD FMT value (uint8_t) or negative on error. */ +int ipacc_rtp_csd_fmt_non_transp(const struct channel_mode_and_rate *ch_mode_rate, + const enum rsl_ipac_rtp_csd_format_d format_d) +{ + uint8_t ret = format_d; + + switch (ch_mode_rate->data_rate.nt) { + case RSL_CMOD_CSD_NTA_43k5_14k5: + case RSL_CMOD_CSD_NTA_43k5_29k0: + case RSL_CMOD_CSD_NTA_14k5_43k5: + case RSL_CMOD_CSD_NTA_29k0_43k5: + case RSL_CMOD_CSD_NT_43k5: + ret |= RSL_IPAC_RTP_CSD_IR_64k << 4; + break; + case RSL_CMOD_CSD_NTA_29k0_14k5: + case RSL_CMOD_CSD_NTA_14k5_29k0: + case RSL_CMOD_CSD_NT_28k8: + ret |= RSL_IPAC_RTP_CSD_IR_32k << 4; + break; + case RSL_CMOD_CSD_NT_14k5: + case RSL_CMOD_CSD_NT_12k0: + ret |= RSL_IPAC_RTP_CSD_IR_16k << 4; + break; + case RSL_CMOD_CSD_NT_6k0: + ret |= RSL_IPAC_RTP_CSD_IR_8k << 4; + break; + default: + return -EINVAL; + } + + return ret; +} + /* Return an ip.access BTS speech mode value (uint8_t) or negative on error. */ int ipacc_speech_mode(enum gsm48_chan_mode tch_mode, enum gsm_chan_t type) { @@ -2612,6 +2892,11 @@ void ipacc_speech_mode_set_direction(uint8_t *speech_mode, bool send) int ipacc_payload_type(enum gsm48_chan_mode tch_mode, enum gsm_chan_t type) { switch (gsm48_chan_mode_to_non_vamos(tch_mode)) { + case GSM48_CMODE_DATA_14k5: + case GSM48_CMODE_DATA_12k0: + case GSM48_CMODE_DATA_6k0: + case GSM48_CMODE_DATA_3k6: + return RTP_PT_CSDATA; case GSM48_CMODE_SPEECH_V1: switch (type) { case GSM_LCHAN_TCH_F: @@ -2696,11 +2981,16 @@ static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv, const port = ntohs(port); lchan->abis_ip.connect_port = port; } + if (TLVP_PRESENT(tv, RSL_IE_OSMO_OSMUX_CID)) { + lchan->abis_ip.osmux.remote_cid_present = true; + lchan->abis_ip.osmux.remote_cid = tlvp_val8(tv, RSL_IE_OSMO_OSMUX_CID, 0); + } LOG_LCHAN(lchan, LOGL_DEBUG, "Rx IPACC %s ACK:" - " BTS=%s:%u conn_id=%u rtp_payload2=0x%02x speech_mode=0x%02x\n", + " BTS=%s:%u conn_id=%u rtp_payload2=0x%02x speech_mode=0x%02x osmux_use=%d osmux_loc_cid=%d\n", label, ip_to_a(lchan->abis_ip.bound_ip), lchan->abis_ip.bound_port, - lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2, lchan->abis_ip.speech_mode); + lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2, lchan->abis_ip.speech_mode, + lchan->abis_ip.osmux.use, lchan->abis_ip.osmux.local_cid); } /*! Send Issue IPA RSL CRCX to configure the RTP port of the BTS. @@ -2722,12 +3012,27 @@ int rsl_tx_ipacc_crcx(const struct gsm_lchan *lchan) dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = chan_nr; - /* 0x1- == receive-only, 0x-1 == EFR codec */ - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + if (lchan->current_ch_indctr == GSM0808_CHAN_DATA) { + msgb_tv_put(msg, RSL_IE_IPAC_RTP_CSD_FMT, lchan->abis_ip.rtp_csd_fmt); + + LOG_LCHAN(lchan, LOGL_DEBUG, + "Sending IPACC CRCX to BTS: rtp_csd_fmt=0x%02x RTP_PAYLOAD=%d (CSD) osmux_use=%d osmux_loc_cid=%d\n", + lchan->abis_ip.rtp_csd_fmt, lchan->abis_ip.rtp_payload, + lchan->abis_ip.osmux.use, lchan->abis_ip.osmux.local_cid); + } else { + /* 0x1- == receive-only, 0x-1 == EFR codec */ + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + + LOG_LCHAN(lchan, LOGL_DEBUG, + "Sending IPACC CRCX to BTS: speech_mode=0x%02x RTP_PAYLOAD=%d osmux_use=%d osmux_loc_cid=%d\n", + lchan->abis_ip.speech_mode, lchan->abis_ip.rtp_payload, + lchan->abis_ip.osmux.use, lchan->abis_ip.osmux.local_cid); + } + msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); + if (lchan->abis_ip.osmux.use) + msgb_tlv_put(msg, RSL_IE_OSMO_OSMUX_CID, 1, &lchan->abis_ip.osmux.local_cid); - LOG_LCHAN(lchan, LOGL_DEBUG, "Sending IPACC CRCX to BTS: speech_mode=0x%02x RTP_PAYLOAD=%d\n", - lchan->abis_ip.speech_mode, lchan->abis_ip.rtp_payload); msg->dst = rsl_chan_link(lchan); @@ -2761,10 +3066,17 @@ struct msgb *rsl_make_ipacc_mdcx(const struct gsm_lchan *lchan, uint32_t dest_ip att_ip = (uint32_t *)msgb_put(msg, sizeof(uint32_t)); *att_ip = htonl(dest_ip); msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, dest_port); - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + + if (lchan->current_ch_indctr == GSM0808_CHAN_DATA) + msgb_tv_put(msg, RSL_IE_IPAC_RTP_CSD_FMT, lchan->abis_ip.rtp_csd_fmt); + else + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); if (lchan->abis_ip.rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, lchan->abis_ip.rtp_payload2); + if (lchan->abis_ip.osmux.use) + msgb_tlv_put(msg, RSL_IE_OSMO_OSMUX_CID, 1, &lchan->abis_ip.osmux.local_cid); msg->dst = rsl_chan_link(lchan); @@ -2782,14 +3094,24 @@ int rsl_tx_ipacc_mdcx(const struct gsm_lchan *lchan) if (!msg) return -EINVAL; - LOG_LCHAN(lchan, LOGL_DEBUG, "Sending IPACC MDCX to BTS:" - " %s:%u rtp_payload=%u rtp_payload2=%u conn_id=%u speech_mode=0x%02x\n", - ip_to_a(lchan->abis_ip.connect_ip), - lchan->abis_ip.connect_port, - lchan->abis_ip.rtp_payload, - lchan->abis_ip.rtp_payload2, - lchan->abis_ip.conn_id, - lchan->abis_ip.speech_mode); + if (lchan->current_ch_indctr == GSM0808_CHAN_DATA) + LOG_LCHAN(lchan, LOGL_DEBUG, "Sending IPACC MDCX to BTS:" + " %s:%u rtp_payload=%u (CSD) rtp_payload2=%u conn_id=%u rtp_csd_fmt=0x%02x\n", + ip_to_a(lchan->abis_ip.connect_ip), + lchan->abis_ip.connect_port, + lchan->abis_ip.rtp_payload, + lchan->abis_ip.rtp_payload2, + lchan->abis_ip.conn_id, + lchan->abis_ip.rtp_csd_fmt); + else + LOG_LCHAN(lchan, LOGL_DEBUG, "Sending IPACC MDCX to BTS:" + " %s:%u rtp_payload=%u rtp_payload2=%u conn_id=%u speech_mode=0x%02x\n", + ip_to_a(lchan->abis_ip.connect_ip), + lchan->abis_ip.connect_port, + lchan->abis_ip.rtp_payload, + lchan->abis_ip.rtp_payload2, + lchan->abis_ip.conn_id, + lchan->abis_ip.speech_mode); return abis_rsl_sendmsg(msg); } @@ -2809,7 +3131,12 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) * address and port number to which it has bound the given logical * channel */ - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_CONN_ID)) { @@ -2817,6 +3144,15 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) return -EINVAL; } + if (!lchan->abis_ip.osmux.use && TLVP_PRESENT(&tv, RSL_IE_OSMO_OSMUX_CID)) { + LOGP(DRSL, LOGL_NOTICE, "Received unexpected IE Osmux CID\n"); + return -EINVAL; + } + if (lchan->abis_ip.osmux.use && !TLVP_PRESENT(&tv, RSL_IE_OSMO_OSMUX_CID)) { + LOGP(DRSL, LOGL_NOTICE, "Mandatory IE Osmux CID missing\n"); + return -EINVAL; + } + ipac_parse_rtp(lchan, &tv, "CRCX"); osmo_fsm_inst_dispatch(lchan->fi_rtp, LCHAN_RTP_EV_IPACC_CRCX_ACK, 0); @@ -2854,7 +3190,12 @@ static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) * it now tells us the IP address and port number to which it has * connected the given logical channel */ - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + ipac_parse_rtp(lchan, &tv, "MDCX"); osmo_fsm_inst_dispatch(lchan->fi_rtp, LCHAN_RTP_EV_IPACC_MDCX_ACK, 0); @@ -2882,7 +3223,12 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg) - sizeof(*dh)) < 0) { + LOG_LCHAN(msg->lchan, LOGL_ERROR, "Failed to parse RSL %s\n", + rsl_or_ipac_msg_name(dh->c.msg_type)); + return -EINVAL; + } + LOG_LCHAN(msg->lchan, LOGL_NOTICE, "Rx IPACC DLCX IND%s\n", rsl_cause_name(&tv)); @@ -2895,6 +3241,9 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); int rc = 0; + if (msgb_l2len(msg) < sizeof(*rllh)) + return -EINVAL; + msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, "Abis RSL rx IPACC: "); |