aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-bts/Makefile.am1
-rw-r--r--include/osmo-bts/asci.h20
-rw-r--r--include/osmo-bts/bts.h3
-rw-r--r--include/osmo-bts/l1sap.h2
-rw-r--r--include/osmo-bts/lchan.h10
-rw-r--r--include/osmo-bts/rsl.h5
-rw-r--r--src/common/Makefile.am1
-rw-r--r--src/common/asci.c190
-rw-r--r--src/common/bts.c3
-rw-r--r--src/common/l1sap.c47
-rw-r--r--src/common/lchan.c5
-rw-r--r--src/common/oml.c7
-rw-r--r--src/common/rsl.c67
-rw-r--r--src/osmo-bts-sysmo/oml.c4
14 files changed, 345 insertions, 20 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index 1a072871..0b4058d2 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -1,6 +1,7 @@
noinst_HEADERS = \
abis.h \
abis_osmo.h \
+ asci.h \
bts.h \
bts_model.h \
bts_shutdown_fsm.h \
diff --git a/include/osmo-bts/asci.h b/include/osmo-bts/asci.h
new file mode 100644
index 00000000..fae9ddee
--- /dev/null
+++ b/include/osmo-bts/asci.h
@@ -0,0 +1,20 @@
+#pragma once
+#include <stdint.h>
+
+#include <osmo-bts/lchan.h>
+
+enum {
+ VGCS_TALKER_NONE = 0,
+ VGCS_TALKER_WAIT_FRAME,
+ VGCS_TALKER_ACTIVE,
+};
+
+void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn);
+
+void vgcs_lchan_react(struct gsm_lchan *lchan);
+
+void vgcs_talker_frame(struct gsm_lchan *lchan);
+
+void vgcs_talker_reset(struct gsm_lchan *lchan);
+
+void vgcs_listener_reset(struct gsm_lchan *lchan);
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index a17278e4..191a9f4e 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -25,6 +25,7 @@ enum {
BTS_CTR_RACH_RCVD,
BTS_CTR_RACH_DROP,
BTS_CTR_RACH_HO,
+ BTS_CTR_RACH_VGCS,
BTS_CTR_RACH_CS,
BTS_CTR_RACH_PS,
BTS_CTR_AGCH_RCVD,
@@ -239,6 +240,7 @@ struct gsm_bts {
} interference;
unsigned int t200_ms[7];
unsigned int t3105_ms;
+ unsigned int t3115_ms; /* VGCS UPLINK GRANT repeat timer */
struct {
uint8_t overload_period;
struct {
@@ -261,6 +263,7 @@ struct gsm_bts {
} rach;
} load;
uint8_t ny1;
+ uint8_t ny2; /* maximum number of repetitions for the VGCS UPLINK GRANT */
uint8_t max_ta;
/* AGCH queuing */
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h
index 9a3e0eb2..87e1a990 100644
--- a/include/osmo-bts/l1sap.h
+++ b/include/osmo-bts/l1sap.h
@@ -141,6 +141,8 @@ int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
+void radio_link_timeout_reset(struct gsm_lchan *lchan);
+
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
uint8_t *data, int len);
diff --git a/include/osmo-bts/lchan.h b/include/osmo-bts/lchan.h
index 80ebb0c8..f4da04d6 100644
--- a/include/osmo-bts/lchan.h
+++ b/include/osmo-bts/lchan.h
@@ -303,6 +303,16 @@ struct gsm_lchan {
/* counts up to Ny1 */
unsigned int phys_info_count;
} ho;
+ struct {
+ bool listener_detected;
+ uint8_t talker_active;
+ uint8_t ref;
+ uint32_t fn;
+ /* T3115: VGCS UPLINK GRANT retransmission */
+ struct osmo_timer_list t3115;
+ /* counts up to Ny2 */
+ unsigned int vgcs_ul_grant_count;
+ } asci;
/* S counter for link loss */
int s;
/* Kind of the release/activation. E.g. RSL or PCU */
diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h
index 7f31ea9a..e3950e42 100644
--- a/include/osmo-bts/rsl.h
+++ b/include/osmo-bts/rsl.h
@@ -4,6 +4,9 @@
#define LCHAN_FN_DUMMY 0xFFFFFFFF
#define LCHAN_FN_WAIT 0xFFFFFFFE
+bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt);
+bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt);
+
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg);
int rsl_tx_rf_res(struct gsm_bts_trx *trx);
int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime,
@@ -14,6 +17,8 @@ int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause);
int rsl_tx_conn_fail(const struct gsm_lchan *lchan, uint8_t cause);
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan);
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay);
+int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
+int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay);
/* call-back for LAPDm code, called when it wants to send msgs UP */
int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 270139c9..5cd7909e 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -41,6 +41,7 @@ libbts_a_SOURCES = \
paging.c \
measurement.c \
amr.c \
+ asci.c \
lchan.c \
load_indication.c \
pcu_sock.c \
diff --git a/src/common/asci.c b/src/common/asci.c
new file mode 100644
index 00000000..ccaacd8e
--- /dev/null
+++ b/src/common/asci.c
@@ -0,0 +1,190 @@
+/* ASCI (VGCS/VBS) related common code */
+
+/* (C) 2023 by Harald Welte <laforge@osmocom.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/rsl.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/bts_model.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/l1sap.h>
+#include <osmo-bts/asci.h>
+
+static int tx_vgcs_ul_grant(struct gsm_lchan *lchan)
+{
+ struct gsm0408_vgcs_ul_grant ul_grant;
+ struct gsm_time gt;
+ struct msgb *msg;
+
+ gsm_fn2gsmtime(&gt, lchan->asci.fn);
+
+ /* build the RR VGCS UPLINK GRANT message as per TS 44.018 Section 9.1.49 */
+ ul_grant = (struct gsm0408_vgcs_ul_grant) {
+ .hdr = {
+ .proto_discr = GSM48_PDISC_RR,
+ .msg_type = GSM48_MT_RR_VGCS_UPL_GRANT,
+ },
+ .req_ref = {
+ .ra = lchan->asci.ref,
+ .t1 = gt.t1,
+ .t2 = gt.t2,
+ .t3_low = gt.t3 & 7,
+ .t3_high = gt.t3 >> 3,
+ },
+ .ta = lchan->ta_ctrl.current,
+ };
+
+ /* Wrap it in a RSL UNITDATA REQUEST */
+ msg = rsl_rll_simple(RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan), 0x00, 0);
+ msg->l3h = msg->tail; /* emulate rsl_rx_rll() behaviour */
+ msgb_tl16v_put(msg, RSL_IE_L3_INFO, sizeof(ul_grant), (uint8_t *) &ul_grant);
+
+ /* send it towards MS, just like a RSL message from the BSC */
+ return lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
+}
+
+/* timer call-back for T3115 (VGCS UPLINK GRANT re-transmit) */
+static void vgcs_t3115_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "T3115 timeout (%d resends left)\n",
+ bts->ny2 - lchan->asci.vgcs_ul_grant_count);
+
+ if (lchan->state != LCHAN_S_ACTIVE) {
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "is not active. It is in state %s. Ignoring\n",
+ gsm_lchans_name(lchan->state));
+ return;
+ }
+
+ if (lchan->asci.vgcs_ul_grant_count >= bts->ny2) {
+ lchan->asci.vgcs_ul_grant_count = 0;
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "NY2 reached, sending CONNection FAILure to BSC.\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_TALKER_ACC_FAIL);
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+ return;
+ }
+
+ tx_vgcs_ul_grant(lchan);
+ lchan->asci.vgcs_ul_grant_count++;
+ osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
+}
+
+/* Received random access on dedicated channel. */
+void vgcs_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay, uint32_t fn)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_NOTICE, "VGCS RACH on dedicated channel type %s received with "
+ "TA=%u, ref=%u\n", gsm_lchant_name(lchan->type), acc_delay, ra);
+
+ if (ra == 0x25) { /* See TS 44.018 Table 9.1.45.1 */
+ /* Listener Detection (TS 48.058 Section 4.14) */
+ if (!lchan->asci.listener_detected) {
+ rsl_tx_listener_det(lchan, &acc_delay);
+ lchan->asci.listener_detected = true;
+ }
+ } else {
+ /* Talker Detection (TS 48.058 Section 4.13) */
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ /* Talker detection on group channels only */
+ if (!rsl_chan_rt_is_vgcs(lchan->rsl_chan_rt))
+ return;
+
+ if (lchan->asci.talker_active != VGCS_TALKER_NONE) {
+ LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Ignoring RACH, there is an active talker already.\n");
+ return;
+ }
+
+ /* Set timing advance, power level and activate SACCH */
+ lchan->ta_ctrl.current = acc_delay;
+ lchan->ms_power_ctrl.current = lchan->ms_power_ctrl.max;
+ lchan->want_dl_sacch_active = true;
+
+ /* Stop RACH detection, wait for valid frame */
+ lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
+ if (l1sap_chan_modify(lchan->ts->trx, gsm_lchan2chan_nr(lchan)) != 0) {
+ LOGPLCHAN(lchan, DASCI, LOGL_ERROR, "failed to modify channel after TALKER DET\n");
+ rsl_tx_conn_fail(lchan, RSL_ERR_TALKER_ACC_FAIL);
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+ return;
+ }
+
+ lchan->asci.ref = ra;
+ lchan->asci.fn = fn;
+
+ /* Send TALKER DETECT via RSL to BSC */
+ rsl_tx_talker_det(lchan, &acc_delay);
+
+ /* Send VGCS UPLINK GRANT */
+ lchan->asci.vgcs_ul_grant_count = 1;
+ tx_vgcs_ul_grant(lchan);
+
+ /* Start T3115 */
+ LOGPLCHAN(lchan, DASCI, LOGL_DEBUG, "Starting T3115 with %u ms\n", bts->t3115_ms);
+ lchan->asci.t3115.cb = vgcs_t3115_cb;
+ lchan->asci.t3115.data = lchan;
+ osmo_timer_schedule(&lchan->asci.t3115, 0, bts->t3115_ms * 1000);
+ }
+}
+
+/* Received channel reactivation. (for assignment) */
+void vgcs_lchan_react(struct gsm_lchan *lchan)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Channel is activated for assignment.\n");
+ lchan->asci.talker_active = VGCS_TALKER_WAIT_FRAME;
+ radio_link_timeout_reset(lchan);
+}
+
+/* Received first valid data frame on dedicated channel. */
+void vgcs_talker_frame(struct gsm_lchan *lchan)
+{
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "First valid frame detected, talker now active.\n");
+ osmo_timer_del(&lchan->asci.t3115);
+ lchan->asci.talker_active = VGCS_TALKER_ACTIVE;
+ radio_link_timeout_reset(lchan);
+}
+
+/* Release VGCS Talker state. */
+void vgcs_talker_reset(struct gsm_lchan *lchan)
+{
+ if (lchan->asci.talker_active == VGCS_TALKER_NONE)
+ return;
+
+ LOGPLCHAN(lchan, DASCI, LOGL_INFO, "Uplink released, no talker.\n");
+
+ /* Stop T3115 */
+ osmo_timer_del(&lchan->asci.t3115);
+
+ /* Talker detection done */
+ lchan->asci.talker_active = VGCS_TALKER_NONE;
+}
+
+/* Release VGCS Listener state. */
+void vgcs_listener_reset(struct gsm_lchan *lchan)
+{
+ lchan->asci.listener_detected = false;
+}
diff --git a/src/common/bts.c b/src/common/bts.c
index 3141eef6..a611a9d0 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -94,6 +94,7 @@ static const struct rate_ctr_desc bts_ctr_desc[] = {
[BTS_CTR_RACH_RCVD] = {"rach:rcvd", "Received RACH requests (Um)"},
[BTS_CTR_RACH_DROP] = {"rach:drop", "Dropped RACH requests (Um)"},
[BTS_CTR_RACH_HO] = {"rach:handover", "Received RACH requests (Handover)"},
+ [BTS_CTR_RACH_VGCS] = {"rach:vgcs", "Received RACH requests (VGCS)"},
[BTS_CTR_RACH_CS] = {"rach:cs", "Received RACH requests (CS/Abis)"},
[BTS_CTR_RACH_PS] = {"rach:ps", "Received RACH requests (PS/PCU)"},
@@ -343,7 +344,9 @@ int bts_init(struct gsm_bts *bts)
bts->rtp_jitter_buf_ms = 100;
bts->max_ta = 63;
bts->ny1 = 4;
+ bts->ny2 = 4;
bts->t3105_ms = 300;
+ bts->t3115_ms = 300;
bts->min_qual_rach = MIN_QUAL_RACH;
bts->min_qual_norm = MIN_QUAL_NORM;
bts->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index 7f61f2cd..1c43f8ff 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -57,6 +57,7 @@
#include <osmo-bts/rtp_input_preen.h>
#include <osmo-bts/pcuif_proto.h>
#include <osmo-bts/cbch.h>
+#include <osmo-bts/asci.h>
/* determine the CCCH block number based on the frame number */
unsigned int l1sap_fn2ccch_block(uint32_t fn)
@@ -677,6 +678,10 @@ static void process_l1sap_meas_data(struct gsm_lchan *lchan,
uint32_t fn;
const char *ind_name;
+ /* Do not process measurement reports from non-active VGCS calls. */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt) && lchan->asci.talker_active != VGCS_TALKER_ACTIVE)
+ return;
+
switch (ind_type) {
case PRIM_MPH_INFO:
/* (legacy way, see also OS#2977) */
@@ -1540,6 +1545,14 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx,
return 0;
}
+/* Reset link timeout to current value. */
+void radio_link_timeout_reset(struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+
+ lchan->s = bts->radio_link_timeout.current;
+}
+
/* process radio link timeout counter S. Follows TS 05.08 Section 5.2
* "MS Procedure" as the "BSS Procedure [...] shall be determined by the
* network operator." */
@@ -1547,6 +1560,11 @@ static void radio_link_timeout(struct gsm_lchan *lchan, bool bad_frame)
{
struct gsm_bts *bts = lchan->ts->trx->bts;
+ /* Bypass radio link timeout on VGCS/VBS channels: There is no
+ * uplink SACCH on these when talker is not active. */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt) && lchan->asci.talker_active != VGCS_TALKER_ACTIVE)
+ return;
+
/* Bypass radio link timeout if set to -1 */
if (bts->radio_link_timeout.current < 0)
return;
@@ -1764,6 +1782,10 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx,
if (lchan->ho.active == HANDOVER_WAIT_FRAME)
handover_frame(lchan);
+ /* report first valid received frame to VGCS talker process */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt) && lchan->asci.talker_active == VGCS_TALKER_WAIT_FRAME)
+ vgcs_talker_frame(lchan);
+
if (L1SAP_IS_LINK_SACCH(link_id))
le = &lchan->lapdm_ch.lapdm_acch;
else
@@ -1882,7 +1904,6 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap,
LOGPLCGT(lchan, &g_time, DL1P, LOGL_DEBUG, "Rx TCH.ind\n");
}
-
/* The ph_tch_param contained in the l1sap primitive may contain
* measurement data. If this data is present, forward it for
* processing */
@@ -1958,17 +1979,26 @@ static bool rach_pass_filter(struct ph_rach_ind_param *rach_ind, struct gsm_bts
return true;
}
-/* Special case where handover RACH is detected */
-static int l1sap_handover_rach(struct gsm_bts_trx *trx, struct ph_rach_ind_param *rach_ind)
+/* Special case where RACH on DCCH uplink is detected */
+static int l1sap_dcch_rach(struct gsm_bts_trx *trx, struct ph_rach_ind_param *rach_ind)
{
+ struct gsm_lchan *lchan;
+
/* Filter out noise / interference / ghosts */
- if (!rach_pass_filter(rach_ind, trx->bts, "handover")) {
+ if (!rach_pass_filter(rach_ind, trx->bts, "DCCH")) {
rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_DROP);
return 0;
}
- handover_rach(get_lchan_by_chan_nr(trx, rach_ind->chan_nr),
- rach_ind->ra, rach_ind->acc_delay);
+ lchan = get_lchan_by_chan_nr(trx, rach_ind->chan_nr);
+ /* Differentiate + dispatch hand-over and VGCS RACH */
+ if (rsl_chan_rt_is_asci(lchan->rsl_chan_rt)) {
+ rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_VGCS);
+ vgcs_rach(lchan, rach_ind->ra, rach_ind->acc_delay, rach_ind->fn);
+ } else {
+ rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_HO);
+ handover_rach(lchan, rach_ind->ra, rach_ind->acc_delay);
+ }
/* must return 0, so in case of msg at l1sap, it will be freed */
return 0;
@@ -2019,8 +2049,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
/* TODO: do we need to count Access Bursts on PDCH? */
return l1sap_pdch_rach(trx, rach_ind);
default:
- rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_HO);
- return l1sap_handover_rach(trx, rach_ind);
+ return l1sap_dcch_rach(trx, rach_ind);
}
rate_ctr_inc2(trx->bts->ctrs, BTS_CTR_RACH_RCVD);
@@ -2238,7 +2267,7 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr)
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "Activating channel %s\n", rsl_chan_nr_str(chan_nr));
- lchan->s = trx->bts->radio_link_timeout.current;
+ radio_link_timeout_reset(lchan);
rc = l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_ACTIVATE, 0);
if (rc)
diff --git a/src/common/lchan.c b/src/common/lchan.c
index 8d2b6496..971f0a5d 100644
--- a/src/common/lchan.c
+++ b/src/common/lchan.c
@@ -33,6 +33,7 @@
#include <osmo-bts/handover.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/bts_model.h>
+#include <osmo-bts/asci.h>
#include <errno.h>
static const struct value_string lchan_s_names[] = {
@@ -216,8 +217,10 @@ void gsm_lchan_release(struct gsm_lchan *lchan, enum lchan_rel_act_kind rel_kind
if (lchan->state == LCHAN_S_NONE)
return;
- /* release handover state */
+ /* release handover, listener and talker states */
handover_reset(lchan);
+ vgcs_talker_reset(lchan);
+ vgcs_listener_reset(lchan);
lchan->rel_act_kind = rel_kind;
diff --git a/src/common/oml.c b/src/common/oml.c
index 361f59e2..43802583 100644
--- a/src/common/oml.c
+++ b/src/common/oml.c
@@ -729,11 +729,16 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE);
}
bts->t3105_ms = t3105 * 10;
+ /* there are no OML IEs for T3115; let's use T3105 as HO detection is a similar procedure */
+ bts->t3115_ms = bts->t3105_ms;
}
/* 9.4.37 NY1 */
- if (TLVP_PRES_LEN(&tp, NM_ATT_NY1, 1))
+ if (TLVP_PRES_LEN(&tp, NM_ATT_NY1, 1)) {
bts->ny1 = *TLVP_VAL(&tp, NM_ATT_NY1);
+ /* there are no OML IEs for NY2; let's use NY1 as HO detection is a similar procedure */
+ bts->ny2 = bts->ny1;
+ }
/* 9.4.8 BCCH ARFCN */
if (TLVP_PRES_LEN(&tp, NM_ATT_BCCH_ARFCN, 2))
diff --git a/src/common/rsl.c b/src/common/rsl.c
index b71310a4..9bdc7303 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -57,6 +57,7 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/pcuif_proto.h>
#include <osmo-bts/notification.h>
+#include <osmo-bts/asci.h>
//#define FAKE_CIPH_MODE_COMPL
@@ -64,6 +65,31 @@
#define BS_POWER2DB(bs_power) \
((bs_power & 0x0f) * 2)
+bool rsl_chan_rt_is_asci(enum rsl_cmod_crt chan_rt)
+{
+ switch (chan_rt) {
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ case RSL_CMOD_CRT_TCH_BCAST_Bm:
+ case RSL_CMOD_CRT_TCH_BCAST_Lm:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool rsl_chan_rt_is_vgcs(enum rsl_cmod_crt chan_rt)
+{
+ switch (chan_rt) {
+ case RSL_CMOD_CRT_TCH_GROUP_Bm:
+ case RSL_CMOD_CRT_TCH_GROUP_Lm:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause, const uint8_t *chan_nr,
const uint8_t *link_id, const struct msgb *orig_msg);
@@ -1412,28 +1438,50 @@ static int rsl_tx_chan_act_ack(struct gsm_lchan *lchan)
return abis_bts_rsl_sendmsg(msg);
}
-/* 8.4.7 sending HANDOver DETection */
-int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
+/* common helper function for *_DETECT */
+static int _rsl_tx_detect(struct gsm_lchan *lchan, uint8_t msg_type, uint8_t *acc_delay)
{
struct msgb *msg;
uint8_t chan_nr = gsm_lchan2chan_nr_rsl(lchan);
- LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
-
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
if (!msg)
return -ENOMEM;
/* 9.3.17 Access Delay */
- if (ho_delay)
- msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *ho_delay);
+ if (acc_delay)
+ msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, *acc_delay);
- rsl_dch_push_hdr(msg, RSL_MT_HANDO_DET, chan_nr);
+ rsl_dch_push_hdr(msg, msg_type, chan_nr);
msg->trx = lchan->ts->trx;
return abis_bts_rsl_sendmsg(msg);
}
+/* 8.4.7 sending HANDOver DETection */
+int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending HANDOver DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_HANDO_DET, ho_delay);
+}
+
+/* 8.4.22 sending LISTENER DETection */
+int rsl_tx_listener_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending LISTENER DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_LISTENER_DET, acc_delay);
+}
+
+/* 8.4.21 sending TALKER DETection */
+int rsl_tx_talker_det(struct gsm_lchan *lchan, uint8_t *acc_delay)
+{
+ LOGPLCHAN(lchan, DRSL, LOGL_INFO, "Sending TALKER DETect\n");
+
+ return _rsl_tx_detect(lchan, RSL_MT_TALKER_DET, acc_delay);
+}
+
/* 8.4.3 sending CHANnel ACTIVation Negative ACK */
static int _rsl_tx_chan_act_nack(struct gsm_bts_trx *trx, uint8_t chan_nr, uint8_t cause,
struct gsm_lchan *lchan)
@@ -3452,6 +3500,10 @@ static int rsl_rx_rll(struct gsm_bts_trx *trx, struct msgb *msg)
return -1;
}
+ /* VGCS Uplink is released by MSC using REL-REQ. */
+ if (rh->c.msg_type == RSL_MT_REL_REQ)
+ vgcs_talker_reset(lchan);
+
LOGPLCHAN(lchan, DRLL, LOGL_DEBUG, "Rx RLL %s Abis -> LAPDm\n", rsl_msg_name(rh->c.msg_type));
/* make copy of RLL header, as the message will be free'd in case of erroneous return */
@@ -3672,6 +3724,7 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
/* REL_IND handling */
if (rh->msg_type == RSL_MT_REL_IND && lchan_is_tch(lchan)) {
+ vgcs_talker_reset(lchan);
LOGPLCHAN(lchan, DRSL, LOGL_INFO,
"Scheduling %s to L3 in next associated TCH-RTS.ind\n",
rsl_msg_name(rh->msg_type));
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index 5ac72f2a..9b760a35 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -1172,8 +1172,8 @@ int lchan_activate(struct gsm_lchan *lchan)
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Trying to activate lchan, but commands in queue\n");
/* For handover, always start the main channel immediately. lchan->want_dl_sacch_active indicates whether dl
- * SACCH should be activated. Also, for HO, start the RACH SAPI. */
- if (lchan->ho.active == HANDOVER_ENABLED)
+ * SACCH should be activated. Also, for HO and VGCS listener/talker detection, start the RACH SAPI. */
+ if (lchan->ho.active == HANDOVER_ENABLED || rsl_chan_rt_is_asci(lchan->rsl_chan_rt))
enqueue_sapi_act_cmd(lchan, GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink);
for (i = 0; i < s4l->num_sapis; i++) {