aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/abis_rsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/abis_rsl.c')
-rw-r--r--src/osmo-bsc/abis_rsl.c711
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: ");