diff options
-rw-r--r-- | include/osmo-bts/Makefile.am | 1 | ||||
-rw-r--r-- | include/osmo-bts/asci.h | 20 | ||||
-rw-r--r-- | include/osmo-bts/bts.h | 3 | ||||
-rw-r--r-- | include/osmo-bts/l1sap.h | 2 | ||||
-rw-r--r-- | include/osmo-bts/lchan.h | 10 | ||||
-rw-r--r-- | include/osmo-bts/rsl.h | 5 | ||||
-rw-r--r-- | src/common/Makefile.am | 1 | ||||
-rw-r--r-- | src/common/asci.c | 190 | ||||
-rw-r--r-- | src/common/bts.c | 3 | ||||
-rw-r--r-- | src/common/l1sap.c | 47 | ||||
-rw-r--r-- | src/common/lchan.c | 5 | ||||
-rw-r--r-- | src/common/oml.c | 7 | ||||
-rw-r--r-- | src/common/rsl.c | 67 | ||||
-rw-r--r-- | src/osmo-bts-sysmo/oml.c | 4 |
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(>, 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++) { |