ASCI: VGCS/VBS RACH -> RSL TALKER/LISTENER DETECT

Random access is allowed on VGCS / VBS channels to access the uplink or
to detect listeners. Uplink Access from a listener is only reported once
after activating the channel. Uplink Access from a talker is reported
each time the uplink becomes occupied. RSL TALKER/LISTENER DETECT
messages are sent to the bsc.

The VGCS UPLINK GRANT message is sent by the BTS itself. Timer T3115 is
used to repeat the message up to NY2 times until one valid frame is
received from the MS (CM service request). The UPLINK BUSY / UPLINK FREE
message must be sent by the BSC.

The uplink is released by UPLINK RELEASE message from the MS or from the
BSC. Afterwards the UPLINK FREE message causes the MS to leave the
uplink without any acknowlege. An RSL REL-REQ must be used to terminate
the link locally. (Without layer 2 DISC procedure.)

Change-Id: I1bd07ab6802341b09a06e89df356665ffaf6d2bf
Related: OS#4851
This commit is contained in:
Harald Welte 2023-05-11 13:14:20 +02:00 committed by laforge
parent 6c83527e62
commit 2ae45aba3f
14 changed files with 345 additions and 20 deletions

View File

@ -1,6 +1,7 @@
noinst_HEADERS = \
abis.h \
abis_osmo.h \
asci.h \
bts.h \
bts_model.h \
bts_shutdown_fsm.h \

20
include/osmo-bts/asci.h Normal file
View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -41,6 +41,7 @@ libbts_a_SOURCES = \
paging.c \
measurement.c \
amr.c \
asci.c \
lchan.c \
load_indication.c \
pcu_sock.c \

190
src/common/asci.c Normal file
View File

@ -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;
}

View File

@ -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 */

View File

@ -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)

View File

@ -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;

View File

@ -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))

View File

@ -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));

View File

@ -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++) {