gerrit-log
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
July 2023
- 1 participants
- 3051 discussions
[M] Change in osmo-bsc[master]: ASCI: Add support for reception of TALKER/LISTENER DETECTION
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33616 )
(
7 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Add support for reception of TALKER/LISTENER DETECTION
......................................................................
ASCI: Add support for reception of TALKER/LISTENER DETECTION
TALKER DETECTION and LISTENER DETECTION is used when the uplink is
accessed on the VGCS channel by a talker or listener.
Change-Id: I166d6d42c04337e669307943ecbb8eea6906b385
Related: OS#4852
---
M src/osmo-bsc/abis_rsl.c
1 file changed, 79 insertions(+), 2 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index ad288ab..24aee8a 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1544,6 +1544,66 @@
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;
@@ -1611,6 +1671,12 @@
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);
@@ -1641,8 +1707,6 @@
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:
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33616
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I166d6d42c04337e669307943ecbb8eea6906b385
Gerrit-Change-Number: 33616
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33618 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Add assignment to a VGCS/VBS channel
......................................................................
ASCI: Add assignment to a VGCS/VBS channel
The assignment is triggered by the MSC by sending an ASSIGNMENT REQUEST
with a group call reference. The reference is used to find the VGCS/VBS
channel that belogs to the referenced call.
The existing VGCS/VBS channel is reactivated. This will put the channel
into a state where the MS can establish the link on it, to complete the
assignment. The old connection is released by the MSC and assignment
completion is handled by the VGCS FSM.
Change-Id: Idaa864cd5ce4df6c3193494ce12d91523c104d89
Related: OS#4852
---
M include/osmocom/bsc/gsm_data.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/osmo_bsc_bssap.c
4 files changed, 70 insertions(+), 4 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 70be943..7d36baa 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -142,6 +142,7 @@
enum assign_for assign_for;
bool aoip;
+ bool vgcs;
uint16_t msc_assigned_cic;
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 24aee8a..125f0ba 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1652,6 +1652,10 @@
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 {
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 037c256..3ae1367 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -261,9 +261,11 @@
static void assignment_success(struct gsm_subscriber_connection *conn)
{
struct gsm_bts *bts;
- bool lchan_changed = (conn->assignment.new_lchan != NULL);
+ bool lchan_changed = (conn->assignment.new_lchan != NULL && !conn->assignment.req.vgcs);
- /* Take on the new lchan. If there only was a Channel Mode Modify, then there is no new lchan to take on. */
+ /* Take on the new lchan. If there only was a Channel Mode Modify, then there is no new lchan to take on.
+ * In case of VGCS/VBS channel, the assignment is handled by its state machine. This subscriber connection will
+ * be released by MSC. */
if (lchan_changed) {
gscon_change_primary_lchan(conn, conn->assignment.new_lchan);
@@ -569,7 +571,10 @@
return;
}
- if (req->target_lchan) {
+ if (req->vgcs) {
+ /* When assigning to a VGCS/VBS, the target lchan is already defined. */
+ conn->assignment.new_lchan = req->target_lchan;
+ } else if (req->target_lchan) {
bool matching_mode;
/* The caller already picked a target lchan to assign to. No need to try re-using the current lchan or
@@ -643,7 +648,9 @@
req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port,
req->use_osmux ? "yes" : "no");
- assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);
+ /* Wait for lchan to become active before send assignment. In case of VGCS/VBS directly send assignment,
+ * because the channel is already active. */
+ assignment_fsm_state_chg(req->vgcs ? ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE : ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);
}
static void assignment_fsm_wait_lchan_active_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index de059e3..2a98054 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -1089,6 +1089,7 @@
struct msgb *resp;
struct tlv_parsed tp;
struct gsm0808_channel_type ct;
+ struct gsm0808_group_callref gc;
uint8_t cause;
int rc;
struct assignment_request req = {};
@@ -1120,6 +1121,40 @@
goto reject;
}
+ /* Check for assignment to VGCS channel. */
+ if (TLVP_PRESENT(&tp, GSM0808_IE_GROUP_CALL_REFERENCE)) {
+ struct gsm_bts *bts = conn_get_bts(conn);
+
+ OSMO_ASSERT(bts);
+ /* Decode Group Call Reference. */
+ rc = gsm0808_dec_group_callref(&gc, TLVP_VAL(&tp, GSM0808_IE_GROUP_CALL_REFERENCE),
+ TLVP_LEN(&tp, GSM0808_IE_GROUP_CALL_REFERENCE));
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to decode Group Call Reference.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ req.target_lchan = vgcs_vbs_find_lchan(bts, &gc);
+ if (!req.target_lchan) {
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ req.assign_for = ASSIGN_FOR_BSSMAP_REQ;
+ req.vgcs = true;
+
+ /* Copy timing advance. */
+ if (conn->lchan) {
+ req.target_lchan->activate.info.ta_known = conn->lchan->activate.info.ta_known;
+ req.target_lchan->activate.info.ta = conn->lchan->activate.info.ta;
+ }
+
+ /* Send reactivation on target lchan to prepare VGCS channel for assignment.
+ * See patent EP 1 858 275 A1. */
+ rsl_tx_chan_activ(req.target_lchan, RSL_ACT_TYPE_REACT | RSL_ACT_INTRA_NORM_ASS, 0);
+
+ return osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_ASSIGNMENT_START, &req);
+ }
+
bssmap_handle_ass_req_lcls(conn, &tp);
/* Currently we only support a limited subset of all
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33618
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Idaa864cd5ce4df6c3193494ce12d91523c104d89
Gerrit-Change-Number: 33618
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[S] Change in osmo-bsc[master]: ASCI: Send release on VGCS/VBS channel via unit data
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33617 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Send release on VGCS/VBS channel via unit data
......................................................................
ASCI: Send release on VGCS/VBS channel via unit data
Channel release is sent to MS that is in dedicated mode on the main
DCCH. Additionally it is sent as unit data on a VGCS/VBS to notify all
listeners that the channel has been released. All listeners return to
IDLE mode.
Change-Id: Ib777fe98c8ce2342082d88d227b796167d92cfe1
Related: OS#4852
---
M include/osmocom/bsc/gsm_04_08_rr.h
M src/osmo-bsc/gsm_04_08_rr.c
M src/osmo-bsc/lchan_fsm.c
3 files changed, 40 insertions(+), 7 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/include/osmocom/bsc/gsm_04_08_rr.h b/include/osmocom/bsc/gsm_04_08_rr.h
index 3106e77..9a9956b 100644
--- a/include/osmocom/bsc/gsm_04_08_rr.h
+++ b/include/osmocom/bsc/gsm_04_08_rr.h
@@ -18,7 +18,7 @@
void gsm_net_update_ctype(struct gsm_network *network);
enum gsm_chan_t get_ctype_by_chreq(struct gsm_network *network, uint8_t ra);
int get_reason_by_chreq(uint8_t ra, int neci);
-int gsm48_send_rr_release(struct gsm_lchan *lchan);
+int gsm48_send_rr_release(struct gsm_lchan *lchan, bool ui);
int send_siemens_mrpci(struct gsm_lchan *lchan,
uint8_t *classmark2_lv);
int gsm48_send_rr_classmark_enquiry(struct gsm_lchan *lchan);
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index 78a4f45..60ccb5a 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -308,12 +308,15 @@
}
}
+#define REPEAT_RR_RELEASE_UI 3
+
/* 7.1.7 and 9.1.7: RR CHANnel RELease */
-int gsm48_send_rr_release(struct gsm_lchan *lchan)
+int gsm48_send_rr_release(struct gsm_lchan *lchan, bool ui)
{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RR REL");
+ struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RR REL"), *msgc;
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
uint8_t *cause;
+ int n;
msg->lchan = lchan;
gh->proto_discr = GSM48_PDISC_RR;
@@ -338,8 +341,17 @@
gsm_lchan_name(lchan), lchan->release.rr_cause,
rr_cause_name(lchan->release.rr_cause));
- /* Send actual release request to MS */
- return gsm48_sendmsg(msg);
+ /* Send actual release request to MS (dedicated channel) */
+ if (!ui)
+ return gsm48_sendmsg(msg);
+
+ /* Send actual release request to MS (VGCS channel) */
+ for (n = 1; n < REPEAT_RR_RELEASE_UI; n++) {
+ msgc = msgb_copy(msg, "CHAN RELEASE copy");
+ msgc->lchan = lchan;
+ gsm48_sendmsg_unit(msgc);
+ }
+ return gsm48_sendmsg_unit(msg);
}
int send_siemens_mrpci(struct gsm_lchan *lchan,
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 70fb811..26c1882 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -1421,8 +1421,14 @@
static void lchan_do_release(struct gsm_lchan *lchan)
{
- if (lchan->release.do_rr_release && lchan->sapis[0] != LCHAN_SAPI_UNUSED)
- gsm48_send_rr_release(lchan);
+ if (lchan->release.do_rr_release) {
+ /* To main DCCH in dedicated and group transmit mode */
+ if (lchan->sapis[0] != LCHAN_SAPI_UNUSED)
+ gsm48_send_rr_release(lchan, false);
+ /* As UI to all listeners in group receive mode */
+ if (lchan_is_asci(lchan))
+ gsm48_send_rr_release(lchan, true);
+ }
if (lchan->fi_rtp)
osmo_fsm_inst_dispatch(lchan->fi_rtp, LCHAN_RTP_EV_RELEASE, 0);
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33617
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Ib777fe98c8ce2342082d88d227b796167d92cfe1
Gerrit-Change-Number: 33617
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[M] Change in osmo-bsc[master]: Select channel type by enum instead of three boolean
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33736 )
(
2 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: Select channel type by enum instead of three boolean
......................................................................
Select channel type by enum instead of three boolean
struct lchan_activate_info and struct lchan_modify_info use an enum to
define, if the channel type is for a normal channel, a VAMOS channel or
a VGCS/VBS channel.
Change-Id: I21167eb4192c02cd7b5e1574cddb382a3feaebe0
---
M include/osmocom/bsc/lchan.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/bsc_vty.c
M src/osmo-bsc/gsm_04_08_rr.c
M src/osmo-bsc/lchan_fsm.c
M src/osmo-bsc/vgcs_fsm.c
7 files changed, 65 insertions(+), 35 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/include/osmocom/bsc/lchan.h b/include/osmocom/bsc/lchan.h
index 3099c63..c0c5761 100644
--- a/include/osmocom/bsc/lchan.h
+++ b/include/osmocom/bsc/lchan.h
@@ -106,6 +106,13 @@
ACTIVATE_FOR_MODE_MODIFY_RTP,
};
+enum lchan_type_for {
+ LCHAN_TYPE_FOR_NORMAL = 0,
+ LCHAN_TYPE_FOR_VAMOS,
+ LCHAN_TYPE_FOR_VGCS,
+ LCHAN_TYPE_FOR_VBS,
+};
+
extern const struct value_string lchan_activate_mode_names[];
static inline const char *lchan_activate_mode_name(enum lchan_activate_for activ_for)
{ return get_value_string(lchan_activate_mode_names, activ_for); }
@@ -139,10 +146,7 @@
* 7, as described in 3GPP TS 45.002. */
struct optional_val tsc;
- bool vamos;
-
- /* In case of ASCI channel: Flags, if a VGCS channel or VBS channel is activated. */
- bool vgcs, vbs;
+ enum lchan_type_for type_for;
/* A copy of bts->imm_ass_time at the time where Channel Activation was requested. A change in the VTY
* configuration has immediate effect on the value, so make sure we don't get mixed up when it gets changed
@@ -173,7 +177,7 @@
* 7, as described in 3GPP TS 45.002. */
struct optional_val tsc;
- bool vamos;
+ enum lchan_type_for type_for;
};
/* Measurement pre-processing state */
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 125f0ba..3bc5808 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -406,7 +406,7 @@
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, bool vgcs, bool vbs)
+ enum lchan_type_for type_for)
{
int rc;
memset(cm, 0, sizeof(*cm));
@@ -430,24 +430,34 @@
cm->chan_rt = RSL_CMOD_CRT_SDCCH;
break;
case GSM_LCHAN_TCH_F:
- if (vamos)
+ switch (type_for) {
+ case LCHAN_TYPE_FOR_VAMOS:
cm->chan_rt = RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm;
- else if (vgcs)
+ break;
+ case LCHAN_TYPE_FOR_VGCS:
cm->chan_rt = RSL_CMOD_CRT_TCH_GROUP_Bm;
- else if (vbs)
+ break;
+ case LCHAN_TYPE_FOR_VBS:
cm->chan_rt = RSL_CMOD_CRT_TCH_BCAST_Bm;
- else
+ break;
+ default:
cm->chan_rt = RSL_CMOD_CRT_TCH_Bm;
+ }
break;
case GSM_LCHAN_TCH_H:
- if (vamos)
+ switch (type_for) {
+ case LCHAN_TYPE_FOR_VAMOS:
cm->chan_rt = RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm;
- else if (vgcs)
+ break;
+ case LCHAN_TYPE_FOR_VGCS:
cm->chan_rt = RSL_CMOD_CRT_TCH_GROUP_Lm;
- else if (vbs)
+ break;
+ case LCHAN_TYPE_FOR_VBS:
cm->chan_rt = RSL_CMOD_CRT_TCH_BCAST_Lm;
- else
+ break;
+ default:
cm->chan_rt = RSL_CMOD_CRT_TCH_Lm;
+ }
break;
case GSM_LCHAN_NONE:
case GSM_LCHAN_UNKNOWN:
@@ -589,8 +599,7 @@
/* 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,
- lchan->activate.info.vgcs, lchan->activate.info.vbs);
+ 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",
@@ -692,7 +701,7 @@
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);
@@ -727,7 +736,7 @@
if (chan_nr < 0)
return chan_nr;
- rc = channel_mode_from_lchan(&cm, lchan, &lchan->modify.ch_mode_rate, lchan->modify.info.vamos, false, false);
+ rc = channel_mode_from_lchan(&cm, lchan, &lchan->modify.ch_mode_rate, lchan->modify.info.type_for);
if (rc < 0)
return rc;
@@ -765,7 +774,8 @@
/* 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);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 3ae1367..9a53652 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -669,8 +669,9 @@
.ta_known = true,
.tsc_set = req->tsc_set,
.tsc = req->tsc,
- .vamos = conn->assignment.new_lchan->vamos.is_secondary,
};
+ if (conn->assignment.new_lchan->vamos.is_secondary)
+ activ_info.type_for = LCHAN_TYPE_FOR_VAMOS;
lchan_activate(conn->assignment.new_lchan, &activ_info);
}
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index e53b145..7918d81 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -870,7 +870,6 @@
.modify_for = MODIFY_FOR_VTY,
.ch_mode_rate = lchan->current_ch_mode_rate,
.ch_indctr = lchan->current_ch_indctr,
- .vamos = vamos,
.tsc_set = {
.present = (tsc_set >= 0),
.val = tsc_set,
@@ -880,6 +879,8 @@
.val = tsc,
},
};
+ if (vamos)
+ info.type_for = LCHAN_TYPE_FOR_VAMOS;
lchan_mode_modify(lchan, &info);
return CMD_SUCCESS;
@@ -1640,7 +1641,7 @@
info.ch_mode_rate.chan_rate = chan_t_to_chan_rate(lchan_t);
if (activate == 2 || lchan->vamos.is_secondary) {
- info.vamos = true;
+ info.type_for = LCHAN_TYPE_FOR_VAMOS;
if (lchan->vamos.is_secondary) {
info.tsc_set.present = true;
info.tsc_set.val = 1;
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index 60ccb5a..67896b1 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -758,7 +758,7 @@
}
}
- if (lchan->modify.info.vamos && lchan->modify.tsc_set > 0) {
+ if (lchan->modify.info.type_for == LCHAN_TYPE_FOR_VAMOS && lchan->modify.tsc_set > 0) {
/* Add the Extended TSC Set IE. So far we only need a TSC Set sent for VAMOS.
* Convert from spec conforming "human readable" TSC Set 1-4 to 0-3 on the wire */
msgb_tv_put(msg, GSM48_IE_EXTENDED_TSC_SET, (lchan->modify.tsc_set - 1) & 0x3);
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 26c1882..1b012bd 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -72,7 +72,8 @@
bool lchan_is_asci(struct gsm_lchan *lchan)
{
- if (lchan->activate.info.vgcs || lchan->activate.info.vbs)
+ if (lchan->activate.info.type_for == LCHAN_TYPE_FOR_VGCS ||
+ lchan->activate.info.type_for == LCHAN_TYPE_FOR_VBS)
return true;
return false;
}
@@ -389,7 +390,7 @@
OSMO_ASSERT(lchan && info);
- if ((info->vamos || lchan->vamos.is_secondary)
+ if ((info->type_for == LCHAN_TYPE_FOR_VAMOS || lchan->vamos.is_secondary)
&& !osmo_bts_has_feature(&lchan->ts->trx->bts->features, BTS_FEAT_VAMOS)) {
lchan->last_error = talloc_strdup(lchan->ts->trx, "VAMOS related channel activation requested,"
" but BTS does not support VAMOS");
@@ -492,7 +493,7 @@
{
OSMO_ASSERT(lchan && info);
- if ((info->vamos || lchan->vamos.is_secondary)
+ if ((info->type_for == LCHAN_TYPE_FOR_VAMOS || lchan->vamos.is_secondary)
&& !osmo_bts_has_feature(&lchan->ts->trx->bts->features, BTS_FEAT_VAMOS)) {
lchan->last_error = talloc_strdup(lchan->ts->trx, "VAMOS related Channel Mode Modify requested,"
" but BTS does not support VAMOS");
@@ -739,9 +740,9 @@
{
struct osmo_fsm_inst *fi = lchan->fi;
lchan->activate.ch_mode_rate = lchan->activate.info.ch_mode_rate;
- lchan->activate.ch_mode_rate.chan_mode = (lchan->activate.info.vamos
+ lchan->activate.ch_mode_rate.chan_mode = (lchan->activate.info.type_for == LCHAN_TYPE_FOR_VAMOS)
? gsm48_chan_mode_to_vamos(lchan->activate.info.ch_mode_rate.chan_mode)
- : gsm48_chan_mode_to_non_vamos(lchan->activate.info.ch_mode_rate.chan_mode));
+ : gsm48_chan_mode_to_non_vamos(lchan->activate.info.ch_mode_rate.chan_mode);
if (lchan->activate.ch_mode_rate.chan_mode < 0) {
lchan_fail("Invalid chan_mode: %s", gsm48_chan_mode_name(lchan->activate.info.ch_mode_rate.chan_mode));
return -EINVAL;
@@ -1008,7 +1009,7 @@
lchan->current_ch_mode_rate = lchan->activate.ch_mode_rate;
lchan->current_mr_conf = lchan->activate.mr_conf_filtered;
lchan->current_ch_indctr = lchan->activate.ch_indctr;
- lchan->vamos.enabled = lchan->activate.info.vamos;
+ lchan->vamos.enabled = (lchan->activate.info.type_for == LCHAN_TYPE_FOR_VAMOS);
lchan->tsc_set = lchan->activate.tsc_set;
lchan->tsc = lchan->activate.tsc;
}
@@ -1197,7 +1198,7 @@
lchan->current_ch_indctr = lchan->modify.ch_indctr;
lchan->tsc_set = lchan->modify.tsc_set;
lchan->tsc = lchan->modify.tsc;
- lchan->vamos.enabled = lchan->modify.info.vamos;
+ lchan->vamos.enabled = (lchan->modify.info.type_for == LCHAN_TYPE_FOR_VAMOS);
if (bsc_chan_ind_requires_rtp_stream(lchan->modify.info.ch_indctr) && !lchan->fi_rtp) {
/* Continue with RTP stream establishing as done in lchan_activate(). Place the requested values in
@@ -1356,9 +1357,9 @@
use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan);
lchan->modify.ch_mode_rate = lchan->modify.info.ch_mode_rate;
- lchan->modify.ch_mode_rate.chan_mode = (lchan->modify.info.vamos
- ? gsm48_chan_mode_to_vamos(lchan->modify.info.ch_mode_rate.chan_mode)
- : gsm48_chan_mode_to_non_vamos(lchan->modify.info.ch_mode_rate.chan_mode));
+ lchan->modify.ch_mode_rate.chan_mode = (lchan->modify.info.type_for == LCHAN_TYPE_FOR_VAMOS)
+ ? gsm48_chan_mode_to_vamos(lchan->modify.info.ch_mode_rate.chan_mode)
+ : gsm48_chan_mode_to_non_vamos(lchan->modify.info.ch_mode_rate.chan_mode);
if (lchan->modify.ch_mode_rate.chan_mode < 0) {
lchan_fail("Invalid chan_mode: %s", gsm48_chan_mode_name(lchan->modify.info.ch_mode_rate.chan_mode));
return;
diff --git a/src/osmo-bsc/vgcs_fsm.c b/src/osmo-bsc/vgcs_fsm.c
index d445eee..6b78933 100644
--- a/src/osmo-bsc/vgcs_fsm.c
+++ b/src/osmo-bsc/vgcs_fsm.c
@@ -616,9 +616,9 @@
.ta = 0,
};
if (conn->vgcs_chan.call->vgcs_call.sf == GSM0808_SF_VGCS)
- info.vgcs = 1;
+ info.type_for = LCHAN_TYPE_FOR_VGCS;
else
- info.vbs = 1;
+ info.type_for = LCHAN_TYPE_FOR_VBS;
/* Activate lchan. If an error occurs, this the function call may trigger VGCS_EV_LCHAN_ERROR event.
* This means that this must be the last action in this handler. */
lchan_activate(conn->vgcs_chan.new_lchan, &info);
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33736
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I21167eb4192c02cd7b5e1574cddb382a3feaebe0
Gerrit-Change-Number: 33736
Gerrit-PatchSet: 3
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[M] Change in osmo-bsc[master]: ASCI: Add decoding of VGCS/VBS A-interface messages
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33612 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Add decoding of VGCS/VBS A-interface messages
......................................................................
ASCI: Add decoding of VGCS/VBS A-interface messages
Change-Id: I77b4d072d76039b1889ae4bba4a602e956405eb8
Related: OS#4852
---
M src/osmo-bsc/osmo_bsc_bssap.c
1 file changed, 125 insertions(+), 0 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index dc0797e..de059e3 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -1298,6 +1298,101 @@
return 0;
}
+/* Handle (VGCS) UPLINK REQUEST ACKNOWLEDGE:
+ *
+ * See 3GPP TS 48.008 §3.2.1.58
+ */
+static int bssmap_handle_uplink_rqst_acknowledge(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ return -1;
+ }
+
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_MSC_ACK, NULL);
+ return 0;
+}
+
+/* Handle (VGCS) UPLINK REJECT COMMAND message.
+ *
+ * See 3GPP TS 48.008 §3.2.1.61
+ */
+static int bssmap_handle_uplink_reject_cmd(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ return -1;
+ }
+
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_MSC_REJECT, NULL);
+ return 0;
+}
+
+/* Handle (VGCS) UPLINK RELEASE COMMAND message, MSC indicating an error to us:
+ *
+ * See 3GPP TS 48.008 §3.2.1.62
+ */
+static int bssmap_handle_uplink_release_cmd(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ return -1;
+ }
+
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_MSC_RELEASE, NULL);
+ return 0;
+}
+
+/* Handle (VGCS) UPLINK SEIZED COMMAND message:
+ *
+ * See 3GPP TS 48.008 §3.2.1.63
+ */
+static int bssmap_handle_uplink_seized_cmd(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ return -1;
+ }
+
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_MSC_SEIZE, NULL);
+ return 0;
+}
+
+/* Handle VGCS/VBS ADDITIONAL INFO message:
+ *
+ * See 3GPP TS 48.008 §3.2.1.78
+ */
+static int bssmap_handle_vgcs_addl_info(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ return -1;
+ }
+
+ LOGPFSML(conn->fi, LOGL_ERROR, "VGCS ADDITIONAL INFO is not supported.\n");
+
+ return 0;
+}
+
static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
struct msgb *msg, unsigned int length)
{
@@ -1401,6 +1496,26 @@
ret = 0;
}
break;
+ case BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UPLINK_RQST_ACKNOWLEDGE]);
+ ret = bssmap_handle_uplink_rqst_acknowledge(conn, msg, length);
+ break;
+ case BSS_MAP_MSG_UPLINK_REJECT_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UPLINK_REJECT_CMD]);
+ ret = bssmap_handle_uplink_reject_cmd(conn, msg, length);
+ break;
+ case BSS_MAP_MSG_UPLINK_RELEASE_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UPLINK_RELEASE_CMD]);
+ ret = bssmap_handle_uplink_release_cmd(conn, msg, length);
+ break;
+ case BSS_MAP_MSG_UPLINK_SEIZED_CMD:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UPLINK_SEIZED_CMD]);
+ ret = bssmap_handle_uplink_seized_cmd(conn, msg, length);
+ break;
+ case BSS_MAP_MSG_VGCS_ADDL_INFO:
+ rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_VGCS_ADDL_INFO]);
+ ret = bssmap_handle_vgcs_addl_info(conn, msg, length);
+ break;
default:
rate_ctr_inc(&ctrs[MSC_CTR_BSSMAP_RX_DT1_UNKNOWN]);
LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33612
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I77b4d072d76039b1889ae4bba4a602e956405eb8
Gerrit-Change-Number: 33612
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[M] Change in osmo-bsc[master]: ASCI: Add encoding of VGCS/VBS A-interface messages
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33610 )
(
5 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Add encoding of VGCS/VBS A-interface messages
......................................................................
ASCI: Add encoding of VGCS/VBS A-interface messages
Change-Id: Ic2203a5119a226ac859a91dc42d81cbd71027ec8
Related: OS#4852
---
M src/osmo-bsc/osmo_bsc_bssap.c
1 file changed, 188 insertions(+), 0 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 096a835..8a999a6 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -49,6 +49,7 @@
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/bsc/lcs_loc_req.h>
#include <osmocom/bsc/bssmap_reset.h>
+#include <osmocom/bsc/assignment_fsm.h>
#define IP_V4_ADDR_LEN 4
@@ -1741,3 +1742,180 @@
LOG_HO(conn, LOGL_ERROR, "Cannot send BSSMAP Handover Failure message (rc=%d %s)\n",
rc, strerror(-rc));
}
+
+/* Send SETUP ACKNOWLEDGE to MSC. */
+void bsc_tx_setup_ack(struct gsm_subscriber_connection *conn, struct gsm0808_vgcs_feature_flags *ff)
+{
+ struct msgb *resp;
+ struct gsm0808_vgcs_vbs_setup_ack sa = {};
+
+ if (ff) {
+ sa.vgcs_feature_flags_present = true;
+ sa.flags = *ff;
+ }
+ resp = gsm0808_create_vgcs_vbs_setup_ack(&sa);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_SETUP_ACK));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send SETUP REFUSE to MSC. */
+void bsc_tx_setup_refuse(struct gsm_subscriber_connection *conn, uint8_t cause)
+{
+ struct msgb *resp;
+ resp = gsm0808_create_vgcs_vbs_setup_refuse(cause);
+
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_SETUP_REFUSE));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send ASSIGNMENT FAILURE to MSC. */
+void bsc_tx_vgcs_vbs_assignment_fail(struct gsm_subscriber_connection *conn, uint8_t cause)
+{
+ struct msgb *resp;
+ struct gsm0808_vgcs_vbs_assign_fail af = {
+ .cause = cause,
+ };
+
+ resp = gsm0808_create_vgcs_vbs_assign_fail(&af);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_ASSIGN_FAIL));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send ASSIGNMENT RESULT to MSC. */
+void bsc_tx_vgcs_vbs_assignment_result(struct gsm_subscriber_connection *conn, struct gsm0808_channel_type *ct,
+ struct gsm0808_cell_id *ci, uint32_t call_id)
+{
+ struct gsm_lchan *lchan = conn->lchan;
+ struct msgb *resp;
+ struct gsm0808_vgcs_vbs_assign_res ar = {
+ .channel_type = *ct,
+ .cell_identifier = *ci,
+ };
+ int perm_spch;
+ uint8_t osmux_cid;
+
+ /* Chosen Channel */
+ ar.chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->current_ch_mode_rate.chan_mode);
+ if (!ar.chosen_channel) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to compose Chosen Channel for mode=%s type=%s",
+ get_value_string(gsm48_chan_mode_names, lchan->current_ch_mode_rate.chan_mode),
+ gsm_chan_t_name(lchan->type));
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ return;
+ }
+ ar.chosen_channel_present = true;
+
+ /* Generate RTP related fields. */
+ if (gscon_is_aoip(conn)) {
+ /* AoIP Transport Layer Address (BSS) */
+ if (!osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(conn->user_plane.mgw_endpoint_ci_msc,
+ &ar.aoip_transport_layer)) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to compose RTP address of MGW -> MSC");
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ return;
+ }
+ ar.aoip_transport_layer_present = true;
+
+ /* Call Identifier */
+ ar.call_id = call_id;
+ ar.call_id_present = true;
+
+ /* Osmux */
+ if (conn->assignment.req.use_osmux) {
+ if (!osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(conn->user_plane.mgw_endpoint_ci_msc,
+ &osmux_cid)) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to compose Osmux CID of MGW -> MSC");
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ return;
+ }
+ }
+
+ /* Extrapolate speech codec from speech mode */
+ perm_spch = gsm0808_permitted_speech(lchan->type, lchan->current_ch_mode_rate.chan_mode);
+ gsm0808_speech_codec_from_chan_type(&ar.codec_msc_chosen, perm_spch);
+ ar.codec_msc_chosen.cfg = conn->lchan->current_ch_mode_rate.s15_s0;
+ ar.codec_present = true;
+ }
+
+ resp = gsm0808_create_vgcs_vbs_assign_res(&ar);
+ OSMO_ASSERT(resp);
+ if (conn->assignment.req.use_osmux)
+ bssap_extend_osmux(resp, osmux_cid);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_VGCS_VBS_ASSIGN_RESULT));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send UPLINK REQUEST to MSC. */
+void bsc_tx_uplink_req(struct gsm_subscriber_connection *conn)
+{
+ struct msgb *resp;
+ struct gsm0808_uplink_request ur = {};
+
+ resp = gsm0808_create_uplink_request(&ur);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_UPLINK_RQST));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send UPLINK REQUEST CONFIRMATION to MSC. */
+void bsc_tx_uplink_req_conf(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length)
+{
+ struct msgb *resp;
+ struct gsm0808_uplink_request_cnf ur = {
+ .cell_identifier = *ci,
+ };
+
+ OSMO_ASSERT(length <= LAYER_3_INFORMATION_MAXLEN);
+ if (length) {
+ memcpy(ur.l3.l3, l3_info, length);
+ ur.l3.l3_len = length;
+ }
+ resp = gsm0808_create_uplink_request_cnf(&ur);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_UPLINK_RQST_CONFIRMATION));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send UPLINK APPLICATION DATA to MSC. */
+void bsc_tx_uplink_app_data(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length)
+{
+ struct msgb *resp;
+ struct gsm0808_uplink_app_data ad = {
+ .cell_identifier = *ci,
+ };
+
+ OSMO_ASSERT(length <= LAYER_3_INFORMATION_MAXLEN);
+ memcpy(ad.l3.l3, l3_info, length);
+ ad.l3.l3_len = length;
+ resp = gsm0808_create_uplink_app_data(&ad);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_UPLINK_APP_DATA));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
+
+/* Send UPLINK RELEASE INDICATION to MSC. */
+void bsc_tx_uplink_release_ind(struct gsm_subscriber_connection *conn, uint8_t cause)
+{
+ struct msgb *resp;
+ struct gsm0808_uplink_release_ind ri = {
+ .cause = cause,
+ };
+
+ resp = gsm0808_create_uplink_release_ind(&ri);
+ OSMO_ASSERT(resp);
+
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_UPLINK_RELEASE_INDICATION));
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
+}
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33610
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Ic2203a5119a226ac859a91dc42d81cbd71027ec8
Gerrit-Change-Number: 33610
Gerrit-PatchSet: 6
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33611 )
Change subject: ASCI: Add processing and FSMs for VGCS/VBS
......................................................................
ASCI: Add processing and FSMs for VGCS/VBS
Change-Id: Id9e94fb4f27bb438b7093c031344a3400bfa34f1
Related: OS#4852
---
M include/osmocom/bsc/Makefile.am
M include/osmocom/bsc/gsm_data.h
A include/osmocom/bsc/vgcs_fsm.h
M src/osmo-bsc/Makefile.am
M src/osmo-bsc/bsc_subscr_conn_fsm.c
M src/osmo-bsc/osmo_bsc_bssap.c
A src/osmo-bsc/vgcs_fsm.c
7 files changed, 1,479 insertions(+), 1 deletion(-)
Approvals:
laforge: Looks good to me, but someone else must approve
Jenkins Builder: Verified
pespin: Looks good to me, approved
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 8baff9c..2010d6b 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -67,4 +67,5 @@
osmo_bsc_lcls.h \
smscb.h \
power_control.h \
+ vgcs_fsm.h \
$(NULL)
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index c2bd7ad..70be943 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -412,6 +412,60 @@
} fast_return;
enum gsm0808_cause clear_cause;
+
+ /* VGCS/VBS "call controling" connection */
+ struct {
+ /* Features supported by MSC/BSC */
+ bool ff_present;
+ struct gsm0808_vgcs_feature_flags ff;
+ /* Group Call Reference IE */
+ struct gsm0808_group_callref gc_ie;
+ enum gsm0808_service_flag sf;
+ uint32_t call_ref;
+ /* Call (BSC) FSM */
+ struct osmo_fsm_inst *fi;
+ /* Current talker */
+ struct gsm_subscriber_connection *talker;
+ /* L3 info of link establihment (Talker established) */
+ struct llist_head l3_queue;
+ /* Flag and cause (Talker released) */
+ bool talker_rel;
+ uint8_t talker_cause;
+ /* Flag that states acknowledgement of the talker by MSC */
+ bool msc_ack;
+ /* List of VGCS/VBS "resource controling" connections */
+ struct llist_head chan_list;
+ } vgcs_call;
+
+ /* VGCS/VBS "resource controling" connection */
+ struct {
+ /* List entry of chan_list of "call controling" connection */
+ struct llist_head list;
+ /* Group Call Reference IE */
+ struct gsm0808_group_callref gc_ie;
+ enum gsm0808_service_flag sf;
+ uint32_t call_ref;
+ /* Channel type IE */
+ struct gsm0808_channel_type ct;
+ /* Channel mode and rate */
+ struct channel_mode_and_rate ch_mode_rate;
+ /* Cell Identifier IE */
+ struct gsm0808_cell_id ci;
+ char ci_str[16];
+ /* Assignment Requirements IE */
+ enum gsm0808_assignment_requirement ar;
+ /* Call Identifier IE */
+ uint32_t call_id;
+ /* Pointer to VGCS/VBS "call controling" gsconn */
+ struct gsm_subscriber_connection *call;
+ /* Cell (BTS) FSM */
+ struct osmo_fsm_inst *fi;
+ /* lchan to be assigned */
+ struct gsm_lchan *new_lchan;
+ /* MGW peer */
+ char msc_rtp_addr[INET6_ADDRSTRLEN];
+ uint16_t msc_rtp_port;
+ } vgcs_chan;
};
diff --git a/include/osmocom/bsc/vgcs_fsm.h b/include/osmocom/bsc/vgcs_fsm.h
new file mode 100644
index 0000000..80ea21f
--- /dev/null
+++ b/include/osmocom/bsc/vgcs_fsm.h
@@ -0,0 +1,121 @@
+/* Handle a call via VGCS/VBCS (Voice Group/Broadcast Call Service). */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Andreas Eversberg
+ *
+ * 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 Affero 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/>.
+ */
+#pragma once
+
+/* Events for both VGCS/VBS state machines. */
+enum vgcs_fsm_event {
+ /* The BSC sets up a VGCS/VBS call. */
+ VGCS_EV_SETUP,
+ /* The BSC wants to assign a VGCS/VBS channel. */
+ VGCS_EV_ASSIGN_REQ,
+ /* The BTS detects a talker on a channel. */
+ VGCS_EV_TALKER_DET,
+ /* The BTS detects a listener on a channel. */
+ VGCS_EV_LISTENER_DET,
+ /* The MSC accepts a talker. */
+ VGCS_EV_MSC_ACK,
+ /* The MSC rejects a talker. */
+ VGCS_EV_MSC_REJECT,
+ /* The MSC seizes all channels. (blocking for calls) */
+ VGCS_EV_MSC_SEIZE,
+ /* The MSC releases all channels. (unblocking for calls) */
+ VGCS_EV_MSC_RELEASE,
+ /* The MSC sends message to talker. (E.g. CONNECT) */
+ VGCS_EV_MSC_DTAP,
+ /* Channel is now active. Waiting for Talker. */
+ VGCS_EV_LCHAN_ACTIVE,
+ /* Channel activation error. */
+ VGCS_EV_LCHAN_ERROR,
+ /* MGW connection is now active. Waiting for Talker. */
+ VGCS_EV_MGW_OK,
+ /* MGW connection error. */
+ VGCS_EV_MGW_FAIL,
+ /* Channel link established. (Talker establised.) */
+ VGCS_EV_TALKER_EST,
+ /* Channel link data. (Talker sends data.) */
+ VGCS_EV_TALKER_DATA,
+ /* Channel link released. (Talker released.) */
+ VGCS_EV_TALKER_REL,
+ /* Channel link failed. (Talker failed.) */
+ VGCS_EV_TALKER_FAIL,
+ /* Channel is blocked by BSC. */
+ VGCS_EV_BLOCK,
+ /* Channel is rejected by BSC. */
+ VGCS_EV_REJECT,
+ /* Channel is unblocked by BSC. */
+ VGCS_EV_UNBLOCK,
+ /* The connection will be destroyed. (free VGCS resources) */
+ VGCS_EV_CLEANUP,
+ /* The calling subscriber has been assigned to the group channel. */
+ VGCS_EV_CALLING_ASSIGNED,
+};
+
+
+/* States of the VGCS/VBS call state machine */
+enum vgcs_call_fsm_state {
+ /* Call is not setup. Initial state when instance is created. */
+ VGCS_CALL_ST_NULL = 0,
+ /* Call is idle. */
+ VGCS_CALL_ST_IDLE,
+ /* Call is busy, due to a talker in this BSC. */
+ VGCS_CALL_ST_BUSY,
+ /* Call is blocked, due to a talker in a different BSC. */
+ VGCS_CALL_ST_BLOCKED,
+};
+
+/* States of the VGCS/VBS channel state machine */
+enum vgcs_chan_fsm_state {
+ /* Channel not assigned. Initial state when instance is created. */
+ VGCS_CHAN_ST_NULL = 0,
+ /* Wait for establishment of VGCS/VBS channel at BTS. */
+ VGCS_CHAN_ST_WAIT_EST,
+ /* Channel active and idle. Channel is marked as uplink busy. */
+ VGCS_CHAN_ST_ACTIVE_BLOCKED,
+ /* Channel active and idle. Channel is marked as uplink free. */
+ VGCS_CHAN_ST_ACTIVE_FREE,
+ /* Channel active and talker was detected, L2 must be established. */
+ VGCS_CHAN_ST_ACTIVE_INIT,
+ /* Channel active and talker established L2. */
+ VGCS_CHAN_ST_ACTIVE_EST,
+ /* Channel active and wait for talker to release L2. */
+ VGCS_CHAN_ST_ACTIVE_REL,
+};
+
+int vgcs_vbs_chan_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+int vgcs_vbs_call_start(struct gsm_subscriber_connection *conn, struct msgb *msg);
+
+int bssmap_handle_ass_req_ct_speech(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
+ struct tlv_parsed *tp, struct gsm0808_channel_type *ct,
+ struct assignment_request *req, uint8_t *cause);
+void bsc_tx_setup_ack(struct gsm_subscriber_connection *conn, struct gsm0808_vgcs_feature_flags *ff);
+void bsc_tx_setup_refuse(struct gsm_subscriber_connection *conn, uint8_t cause);
+void bsc_tx_vgcs_vbs_assignment_result(struct gsm_subscriber_connection *conn, struct gsm0808_channel_type *ct,
+ struct gsm0808_cell_id *ci, uint32_t call_id);
+void bsc_tx_vgcs_vbs_assignment_fail(struct gsm_subscriber_connection *conn, uint8_t cause);
+void bsc_tx_uplink_req(struct gsm_subscriber_connection *conn);
+void bsc_tx_uplink_req_conf(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length);
+void bsc_tx_uplink_app_data(struct gsm_subscriber_connection *conn, struct gsm0808_cell_id *ci, uint8_t *l3_info,
+ uint8_t length);
+void bsc_tx_uplink_release_ind(struct gsm_subscriber_connection *conn, uint8_t cause);
+struct gsm_lchan *vgcs_vbs_find_lchan(struct gsm_bts *bts, struct gsm0808_group_callref *gc);
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index 53c0912..661188e 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -73,6 +73,7 @@
handover_fsm.c \
handover_logic.c \
handover_vty.c \
+ vgcs_fsm.c \
lb.c \
lchan.c \
lchan_fsm.c \
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index c84e6c9..d9abf10 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -50,6 +50,7 @@
#include <osmocom/core/byteswap.h>
#include <osmocom/bsc/lb.h>
#include <osmocom/bsc/lcs_loc_req.h>
+#include <osmocom/bsc/vgcs_fsm.h>
#define S(x) (1 << (x))
@@ -303,6 +304,8 @@
switch (bssmap_type) {
case BSS_MAP_MSG_HANDOVER_RQST:
case BSS_MAP_MSG_PERFORM_LOCATION_RQST:
+ case BSS_MAP_MSG_VGCS_VBS_SETUP:
+ case BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST:
return 0;
default:
@@ -343,6 +346,20 @@
lcs_loc_req_start(conn, msg);
return;
+ case BSS_MAP_MSG_VGCS_VBS_SETUP:
+ rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_RX_DT1_VGCS_VBS_SETUP]);
+ /* VGCS: MSC asks vor voice group/bcast call. */
+ conn_fsm_state_chg(ST_ACTIVE);
+ vgcs_vbs_call_start(conn, msg);
+ return;
+
+ case BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST:
+ rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_RX_DT1_VGCS_VBS_ASSIGN_RQST]);
+ /* VGCS: MSC asks vor resource (channel) for voice group/bcast call. */
+ conn_fsm_state_chg(ST_ACTIVE);
+ vgcs_vbs_chan_start(conn, msg);
+ return;
+
default:
LOGPFSML(fi, LOGL_ERROR, "No support for initial BSSMAP: %s: %s\n",
gsm0808_bssap_name(bs->type), gsm0808_bssmap_name(bssmap_type));
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 8a999a6..dc0797e 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -50,6 +50,7 @@
#include <osmocom/bsc/lcs_loc_req.h>
#include <osmocom/bsc/bssmap_reset.h>
#include <osmocom/bsc/assignment_fsm.h>
+#include <osmocom/bsc/vgcs_fsm.h>
#define IP_V4_ADDR_LEN 4
@@ -1463,7 +1464,10 @@
/* convert DLCI to RSL link ID, store in msg->cb */
OBSC_LINKID_CB(gsm48) = DLCI2RSL_LINK_ID(header->link_id);
- dtap_rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MT_DTAP, gsm48);
+ if (conn->vgcs_call.fi)
+ dtap_rc = osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_MSC_DTAP, gsm48);
+ else
+ dtap_rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MT_DTAP, gsm48);
return dtap_rc;
}
diff --git a/src/osmo-bsc/vgcs_fsm.c b/src/osmo-bsc/vgcs_fsm.c
new file mode 100644
index 0000000..d445eee
--- /dev/null
+++ b/src/osmo-bsc/vgcs_fsm.c
@@ -0,0 +1,1270 @@
+/* Handle VGCS/VBCS calls. (Voice Group/Broadcast Call Service). */
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Andreas Eversberg
+ *
+ * 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 Affero 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/>.
+ */
+
+/* The process consists of two state machnes:
+ *
+ * The VGCS call state machine handles the voice group/broadcast call control.
+ * There is one instance for every call. It controls the uplink states of the
+ * call. They will be reported to the MSC or can be changed by the MSC.
+ * One SCCP connection for is associated with the state machine. This is used
+ * to talk to the MSC about state changes.
+ *
+ * The VGCS channel state machine handles the channel states in each cell.
+ * There is one instance for every cell and every call. The instances are
+ * linked to the call state process. It controls the uplink states of the
+ * channel. They will be reported to the call state machine or can be changed
+ * by the call state machine.
+ * One SCCP connection for every cell is associated with the state machine.
+ * It is used to perform VGCS channel assignment.
+ *
+ */
+
+#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
+#include <osmocom/bsc/osmo_bsc.h>
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/vgcs_fsm.h>
+#include <osmocom/bsc/handover_fsm.h>
+#include <osmocom/bsc/abis_rsl.h>
+#include <osmocom/bsc/lchan_fsm.h>
+#include <osmocom/bsc/lchan_select.h>
+#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
+#include <osmocom/bsc/assignment_fsm.h>
+#include <osmocom/bsc/gsm_08_08.h>
+#include <osmocom/bsc/gsm_04_08_rr.h>
+#include <osmocom/bsc/bts_trx.h>
+#include <osmocom/bsc/bts.h>
+
+#define S(x) (1 << (x))
+
+#define LOG_CALL(conn, level, fmt, args...) \
+ LOGP(DASCI, level, \
+ (conn->vgcs_call.sf == GSM0808_SF_VGCS) ? ("VGCS callref %s: " fmt) : ("VBS callref %s: " fmt), \
+ gsm44068_group_id_string(conn->vgcs_call.call_ref), ##args)
+#define LOG_CHAN(conn, level, fmt, args...) \
+ LOGP(DASCI, level, \
+ (conn->vgcs_chan.sf == GSM0808_SF_VGCS) ? ("VGCS callref %s, cell %s: " fmt) \
+ : ("VBS callref %s, cell %s: " fmt), \
+ gsm44068_group_id_string(conn->vgcs_chan.call_ref), conn->vgcs_chan.ci_str, ##args)
+
+const char *gsm44068_group_id_string(uint32_t callref)
+{
+ static char string[9];
+
+ snprintf(string, sizeof(string), "%08u", callref);
+
+ return string;
+}
+
+static struct osmo_fsm vgcs_call_fsm;
+static struct osmo_fsm vgcs_chan_fsm;
+
+static __attribute__((constructor)) void vgcs_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&vgcs_call_fsm) == 0);
+ OSMO_ASSERT(osmo_fsm_register(&vgcs_chan_fsm) == 0);
+}
+
+static const struct value_string vgcs_fsm_event_names[] = {
+ OSMO_VALUE_STRING(VGCS_EV_SETUP),
+ OSMO_VALUE_STRING(VGCS_EV_ASSIGN_REQ),
+ OSMO_VALUE_STRING(VGCS_EV_TALKER_DET),
+ OSMO_VALUE_STRING(VGCS_EV_LISTENER_DET),
+ OSMO_VALUE_STRING(VGCS_EV_MSC_ACK),
+ OSMO_VALUE_STRING(VGCS_EV_MSC_REJECT),
+ OSMO_VALUE_STRING(VGCS_EV_MSC_SEIZE),
+ OSMO_VALUE_STRING(VGCS_EV_MSC_RELEASE),
+ OSMO_VALUE_STRING(VGCS_EV_MSC_DTAP),
+ OSMO_VALUE_STRING(VGCS_EV_LCHAN_ACTIVE),
+ OSMO_VALUE_STRING(VGCS_EV_LCHAN_ERROR),
+ OSMO_VALUE_STRING(VGCS_EV_MGW_OK),
+ OSMO_VALUE_STRING(VGCS_EV_MGW_FAIL),
+ OSMO_VALUE_STRING(VGCS_EV_TALKER_EST),
+ OSMO_VALUE_STRING(VGCS_EV_TALKER_DATA),
+ OSMO_VALUE_STRING(VGCS_EV_TALKER_REL),
+ OSMO_VALUE_STRING(VGCS_EV_TALKER_FAIL),
+ OSMO_VALUE_STRING(VGCS_EV_BLOCK),
+ OSMO_VALUE_STRING(VGCS_EV_REJECT),
+ OSMO_VALUE_STRING(VGCS_EV_UNBLOCK),
+ OSMO_VALUE_STRING(VGCS_EV_CLEANUP),
+ OSMO_VALUE_STRING(VGCS_EV_CALLING_ASSIGNED),
+ { }
+};
+
+static struct gsm_subscriber_connection *find_calling_subscr_conn(struct gsm_subscriber_connection *conn)
+{
+ struct gsm_subscriber_connection *c;
+
+ llist_for_each_entry(c, &conn->network->subscr_conns, entry) {
+ if (!c->assignment.fi)
+ continue;
+ if (c->assignment.req.target_lchan != conn->lchan)
+ continue;
+ return c;
+ }
+
+ return NULL;
+}
+
+/*
+ * VGCS call FSM
+ */
+
+static void vgcs_call_detach_and_destroy(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct gsm_subscriber_connection *conn = fi->priv, *c;
+ struct msgb *msg;
+
+ /* Flush message queue. */
+ while ((msg = msgb_dequeue(&conn->vgcs_call.l3_queue)))
+ msgb_free(msg);
+
+ /* Detach all cell instances. */
+ while (!llist_empty(&conn->vgcs_call.chan_list)) {
+ c = llist_entry(conn->vgcs_call.chan_list.next, struct gsm_subscriber_connection, vgcs_chan.list);
+ c->vgcs_chan.call = NULL;
+ llist_del(&c->vgcs_chan.list);
+ }
+
+ /* No Talker. */
+ conn->vgcs_call.talker = NULL;
+
+ /* Remove pointer of FSM. */
+ conn->vgcs_call.fi = NULL;
+}
+
+static void vgcs_call_fsm_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ switch (event) {
+ case VGCS_EV_SETUP:
+ LOG_CALL(conn, LOGL_DEBUG, "VGCS/VBS SETUP from MSC.\n");
+ /* MSC sends VGCS/VBS SETUP for a new call. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_IDLE, 0, 0);
+ /* Remove unsupported features. */
+ conn->vgcs_call.ff.tp_ind = 0;
+ conn->vgcs_call.ff.as_ind_circuit = 0;
+ conn->vgcs_call.ff.as_ind_link = 0;
+ conn->vgcs_call.ff.bss_res = 0;
+ conn->vgcs_call.ff.tcp = 0;
+ /* Acknowlege the call. */
+ bsc_tx_setup_ack(conn, &conn->vgcs_call.ff);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_call_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv, *c;
+ struct handover_rr_detect_data *d = data;
+ struct msgb *msg;
+
+ switch (event) {
+ case VGCS_EV_TALKER_DET:
+ LOG_CALL(conn, LOGL_DEBUG, "Talker detected.\n");
+ /* Talker detected on a channel, call becomes busy. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_BUSY, 0, 0);
+ conn->vgcs_call.talker = d->msg->lchan->conn;
+ /* Reset pending states. */
+ while ((msg = msgb_dequeue(&conn->vgcs_call.l3_queue)))
+ msgb_free(msg);
+ conn->vgcs_call.msc_ack = false;
+ conn->vgcs_call.talker_rel = false;
+ /* Report busy uplink to the MSC. */
+ bsc_tx_uplink_req(conn);
+ /* Block all other channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+ if (c == conn->vgcs_call.talker)
+ continue;
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_BLOCK, NULL);
+ }
+ break;
+ case VGCS_EV_LISTENER_DET:
+ LOG_CALL(conn, LOGL_DEBUG, "Listener detected.\n");
+ // Listener detection not supported.
+ break;
+ case VGCS_EV_MSC_SEIZE:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC seizes all channels.\n");
+ /* MSC seizes call (talker on a different BSS), call becomes blocked. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_BLOCKED, 0, 0);
+ /* Block all channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list)
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_BLOCK, NULL);
+ break;
+ case VGCS_EV_MSC_RELEASE:
+ /* Ignore, because there is no blocked channel in this state. */
+ break;
+ case VGCS_EV_MSC_REJECT:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC rejects talker on uplink.\n");
+ /* Race condition: Talker released before the MSC rejects the talker. Ignore! */
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CALL(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ osmo_fsm_inst_term(conn->vgcs_call.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+/* Get L3 info from message, if exists. Return the length or otherwise return 0. */
+int l3_data_from_msg(struct msgb *msg, uint8_t **l3_info)
+{
+ struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
+
+ /* No space for L3 info */
+ if (msgb_l2len(msg) < sizeof(*rllh) + 3 || rllh->data[0] != RSL_IE_L3_INFO)
+ return 0;
+
+ *l3_info = msg->l3h = &rllh->data[3];
+ return msgb_l3len(msg);
+}
+
+static void vgcs_call_fsm_busy(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv, *c;
+ struct msgb *msg = data;
+ uint8_t cause = (data) ? *(uint8_t *)data : 0;
+ uint8_t *l3_info;
+ int l3_len;
+ int rc;
+
+ switch (event) {
+ case VGCS_EV_TALKER_EST:
+ LOG_CALL(conn, LOGL_DEBUG, "Talker established uplink.\n");
+ /* Talker established L2 connection. Sent L3 info to MSC, if MSC already acked, otherwise enqueue. */
+ if (conn->vgcs_call.msc_ack) {
+ LOG_CALL(conn, LOGL_DEBUG, "Sending establishment messages to MSC.\n");
+ l3_len = l3_data_from_msg(msg, &l3_info);
+ if (conn->vgcs_call.talker)
+ bsc_tx_uplink_req_conf(conn, &conn->vgcs_call.talker->vgcs_chan.ci, l3_info, l3_len);
+ else
+ LOG_CALL(conn, LOGL_ERROR, "Talker establishes, but talker not set, please fix!\n");
+ } else {
+ LOG_CALL(conn, LOGL_DEBUG, "No uplink request ack from MSC yet, queue message.\n");
+ msg = msgb_copy(msg, "Queued Talker establishment");
+ if (msg)
+ msgb_enqueue(&conn->vgcs_call.l3_queue, msg);
+ }
+ break;
+ case VGCS_EV_TALKER_DATA:
+ LOG_CALL(conn, LOGL_DEBUG, "Talker sent data on uplink.\n");
+ /* Talker sends data. Sent L3 info to MSC, if MSC already acked, otherwise enqueue. */
+ if (conn->vgcs_call.msc_ack) {
+ LOG_CALL(conn, LOGL_DEBUG, "Sending data messages to MSC.\n");
+ bsc_dtap(conn, 0, msg);
+ } else {
+ LOG_CALL(conn, LOGL_DEBUG, "No uplink request ack from MSC yet, queue message.\n");
+ msg = msgb_copy(msg, "Queued DTAP");
+ if (msg)
+ msgb_enqueue(&conn->vgcs_call.l3_queue, msg);
+ }
+ break;
+ case VGCS_EV_MSC_DTAP:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC sends DTAP message to talker.\n");
+ if (!conn->vgcs_call.talker)
+ msgb_free(data);
+ rc = osmo_fsm_inst_dispatch(conn->vgcs_call.talker->vgcs_chan.fi, VGCS_EV_MSC_DTAP, data);
+ if (rc < 0)
+ msgb_free(data);
+ break;
+ case VGCS_EV_TALKER_REL:
+ LOG_CALL(conn, LOGL_DEBUG, "Talker released on uplink.\n");
+ if (!conn->vgcs_call.msc_ack) {
+ LOG_CALL(conn, LOGL_DEBUG, "Talker released before MSC acknowleded or rejected.\n");
+ conn->vgcs_call.talker_rel = true;
+ conn->vgcs_call.talker_cause = cause;
+ break;
+ }
+talker_released:
+ /* Talker released channel, call becomes idle. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_IDLE, 0, 0);
+ conn->vgcs_call.talker = NULL;
+ /* Report free uplink to the MSC. */
+ bsc_tx_uplink_release_ind(conn, cause);
+ /* Unblock all other channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+ if (c == conn->vgcs_call.talker)
+ continue;
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_UNBLOCK, NULL);
+ }
+ break;
+ case VGCS_EV_MSC_SEIZE:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC seizes all channels. (channels are blocked)\n");
+ /* Race condition: MSC seizes call (talker on a different BSS), call becomes blocked. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_BLOCKED, 0, 0);
+ /* Reject talker. (Forward to chan FSM.) */
+ if (conn->vgcs_call.talker) {
+ osmo_fsm_inst_dispatch(conn->vgcs_call.talker->vgcs_chan.fi, VGCS_EV_REJECT, NULL);
+ conn->vgcs_call.talker = NULL;
+ }
+ /* Block all channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list)
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_BLOCK, NULL);
+ break;
+ case VGCS_EV_MSC_ACK:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC acks talker on uplink.\n");
+ /* MSC acknowledges uplink. Send L3 info to MSC, if talker already established. */
+ conn->vgcs_call.msc_ack = true;
+ /* Send establish message via UPLINK REQUEST CONFIRM, if already received. */
+ msg = msgb_dequeue(&conn->vgcs_call.l3_queue);
+ if (msg) {
+ LOG_CALL(conn, LOGL_DEBUG, "Sending queued establishment messages to MSC.\n");
+ l3_len = l3_data_from_msg(msg, &l3_info);
+ if (conn->vgcs_call.talker)
+ bsc_tx_uplink_req_conf(conn, &conn->vgcs_call.talker->vgcs_chan.ci, l3_info, l3_len);
+ else
+ LOG_CALL(conn, LOGL_ERROR, "MSC acks taker, but talker not set, please fix!\n");
+ msgb_free(msg);
+ }
+ /* Send data messages via UPLINK APPLICATION DATA, if already received. */
+ while ((msg = msgb_dequeue(&conn->vgcs_call.l3_queue))) {
+ LOG_CALL(conn, LOGL_DEBUG, "Sending queued DTAP messages to MSC.\n");
+ bsc_dtap(conn, 0, msg);
+ msgb_free(msg);
+ }
+ /* If there is a pending talker release. */
+ if (conn->vgcs_call.talker_rel) {
+ LOG_CALL(conn, LOGL_DEBUG, "Sending queued talker release messages to MSC.\n");
+ cause = conn->vgcs_call.talker_cause;
+ goto talker_released;
+ }
+ break;
+ case VGCS_EV_MSC_REJECT:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC rejects talker on uplink.\n");
+ /* MSC rejects talker, call becomes idle. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_IDLE, 0, 0);
+ /* Reject talker. (Forward to chan FSM.) */
+ if (conn->vgcs_call.talker)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.talker->vgcs_chan.fi, VGCS_EV_REJECT, NULL);
+ else
+ LOG_CALL(conn, LOGL_ERROR, "MSC rejects, but talker not set, please fix!\n");
+ conn->vgcs_call.talker = NULL;
+ /* Unblock all other channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list) {
+ if (c == conn->vgcs_call.talker)
+ continue;
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_UNBLOCK, NULL);
+ }
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CALL(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ osmo_fsm_inst_term(conn->vgcs_call.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_call_fsm_blocked(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv, *c;
+ struct msgb *msg;
+
+ switch (event) {
+ case VGCS_EV_CALLING_ASSIGNED:
+ LOG_CALL(conn, LOGL_DEBUG, "Calling subscriber assigned and now on uplink.\n");
+ /* Talker detected on a channel, call becomes busy. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_BUSY, 0, 0);
+ conn->vgcs_call.talker = data;
+ /* Reset pending states, but imply that MSC acked this uplink session. */
+ while ((msg = msgb_dequeue(&conn->vgcs_call.l3_queue)))
+ msgb_free(msg);
+ conn->vgcs_call.msc_ack = true;
+ break;
+ case VGCS_EV_TALKER_REL:
+ LOG_CALL(conn, LOGL_DEBUG, "Talker released on uplink.\n");
+ /* Talker release was complete. Ignore. */
+ break;
+ case VGCS_EV_MSC_RELEASE:
+ LOG_CALL(conn, LOGL_DEBUG, "MSC releases all channels. (channels are free)\n");
+ /* MSC releases call (no mor talker on a different BSS), call becomes idle */
+ osmo_fsm_inst_state_chg(fi, VGCS_CALL_ST_IDLE, 0, 0);
+ /* Unblock all channels. */
+ llist_for_each_entry(c, &conn->vgcs_call.chan_list, vgcs_chan.list)
+ osmo_fsm_inst_dispatch(c->vgcs_chan.fi, VGCS_EV_UNBLOCK, NULL);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CALL(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ osmo_fsm_inst_term(conn->vgcs_call.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static const struct osmo_fsm_state vgcs_call_fsm_states[] = {
+ [VGCS_CALL_ST_NULL] = {
+ .name = "NULL",
+ .in_event_mask = S(VGCS_EV_SETUP),
+ .out_state_mask = S(VGCS_CALL_ST_IDLE),
+ .action = vgcs_call_fsm_null,
+ },
+ [VGCS_CALL_ST_IDLE] = {
+ .name = "IDLE",
+ .in_event_mask = S(VGCS_EV_TALKER_DET) |
+ S(VGCS_EV_MSC_SEIZE) |
+ S(VGCS_EV_MSC_RELEASE) |
+ S(VGCS_EV_MSC_REJECT) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CALL_ST_BUSY) |
+ S(VGCS_CALL_ST_BLOCKED) |
+ S(VGCS_CALL_ST_NULL),
+ .action = vgcs_call_fsm_idle,
+ },
+ [VGCS_CALL_ST_BUSY] = {
+ .name = "BUSY",
+ .in_event_mask = S(VGCS_EV_TALKER_EST) |
+ S(VGCS_EV_TALKER_DATA) |
+ S(VGCS_EV_MSC_DTAP) |
+ S(VGCS_EV_TALKER_REL) |
+ S(VGCS_EV_MSC_SEIZE) |
+ S(VGCS_EV_MSC_ACK) |
+ S(VGCS_EV_MSC_REJECT) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CALL_ST_IDLE) |
+ S(VGCS_CALL_ST_BLOCKED) |
+ S(VGCS_CALL_ST_NULL),
+ .action = vgcs_call_fsm_busy,
+ },
+ [VGCS_CALL_ST_BLOCKED] = {
+ .name = "BLOCKED",
+ .in_event_mask = S(VGCS_EV_CALLING_ASSIGNED) |
+ S(VGCS_EV_TALKER_REL) |
+ S(VGCS_EV_MSC_RELEASE) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CALL_ST_IDLE) |
+ S(VGCS_CALL_ST_BUSY) |
+ S(VGCS_CALL_ST_NULL),
+ .action = vgcs_call_fsm_blocked,
+ },
+};
+
+static struct osmo_fsm vgcs_call_fsm = {
+ .name = "vgcs_call",
+ .states = vgcs_call_fsm_states,
+ .num_states = ARRAY_SIZE(vgcs_call_fsm_states),
+ .log_subsys = DASCI,
+ .event_names = vgcs_fsm_event_names,
+ .cleanup = vgcs_call_detach_and_destroy,
+};
+
+/* Handle VGCS/VBS SETUP message.
+ *
+ * See 3GPP TS 48.008 §3.2.1.50
+ */
+int vgcs_vbs_call_start(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ int payload_length = msg->tail - msg->l4h;
+ struct tlv_parsed tp;
+ struct gsm_subscriber_connection *c;
+ struct gsm0808_group_callref *gc = &conn->vgcs_call.gc_ie;
+ int rc;
+ uint8_t cause;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, payload_length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;
+ goto reject;
+ }
+
+ /* Check for mandatory Group Call Reference. */
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_GROUP_CALL_REFERENCE)) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Mandatory group call reference not present.\n");
+ cause = GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING;
+ goto reject;
+ }
+
+ /* Decode Group Call Reference. */
+ rc = gsm0808_dec_group_callref(gc, TLVP_VAL(&tp, GSM0808_IE_GROUP_CALL_REFERENCE),
+ TLVP_LEN(&tp, GSM0808_IE_GROUP_CALL_REFERENCE));
+ if (rc < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Unable to decode group call reference.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ conn->vgcs_call.sf = gc->sf;
+ conn->vgcs_call.call_ref = (osmo_load32be_ext_2(gc->call_ref_hi, 3) << 3) | gc->call_ref_lo;
+
+ /* Check for duplicated callref. */
+ llist_for_each_entry(c, &conn->network->subscr_conns, entry) {
+ if (!c->vgcs_call.fi)
+ continue;
+ if (c == conn)
+ continue;
+ if (conn->vgcs_call.sf == c->vgcs_call.sf
+ && conn->vgcs_call.call_ref == c->vgcs_call.call_ref) {
+ LOG_CALL(conn, LOGL_ERROR, "A %s call with callref %s already exists.\n",
+ (conn->vgcs_call.sf == GSM0808_SF_VGCS) ? "VGCS" : "VBS",
+ gsm44068_group_id_string(conn->vgcs_call.call_ref));
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ }
+
+ /* Decode VGCS Feature Flags */
+ if (TLVP_PRESENT(&tp, GSM0808_IE_VGCS_FEATURE_FLAGS)) {
+ rc = gsm0808_dec_vgcs_feature_flags(&conn->vgcs_call.ff,
+ TLVP_VAL(&tp, GSM0808_IE_VGCS_FEATURE_FLAGS),
+ TLVP_LEN(&tp, GSM0808_IE_VGCS_FEATURE_FLAGS));
+ if (rc < 0) {
+ LOG_CALL(conn, LOGL_ERROR, "Unable to decode feature flags.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ conn->vgcs_call.ff_present = true;
+ }
+
+ /* Create VGCS FSM. */
+ conn->vgcs_call.fi = osmo_fsm_inst_alloc(&vgcs_call_fsm, conn->network, conn, LOGL_DEBUG, NULL);
+ if (!conn->vgcs_call.fi)
+ goto reject;
+
+ /* Init list of cells that are used by the call. */
+ INIT_LLIST_HEAD(&conn->vgcs_call.chan_list);
+
+ /* Init L3 queue. */
+ INIT_LLIST_HEAD(&conn->vgcs_call.l3_queue);
+
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_SETUP, NULL);
+ return 0;
+reject:
+ bsc_tx_setup_refuse(conn, cause);
+ return -EINVAL;
+}
+
+/*
+ * VGCS chan FSM
+ */
+
+static void vgcs_chan_detach_and_destroy(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ if (conn->vgcs_chan.fi->state != VGCS_CHAN_ST_WAIT_EST) {
+ /* Remove call from notification channel. */
+ if (conn->lchan)
+ rsl_notification_cmd(conn->lchan->ts->trx->bts, NULL, &conn->vgcs_chan.gc_ie, NULL);
+ else
+ LOG_CHAN(conn, LOGL_ERROR, "Unable to remove notification, lchan is already gone.\n");
+ }
+
+ /* Detach from call, if not already. */
+ if (conn->vgcs_chan.call) {
+ llist_del(&conn->vgcs_chan.list);
+ conn->vgcs_chan.call = NULL;
+ }
+
+ /* Remove pointer of FSM. */
+ conn->vgcs_chan.fi = NULL;
+}
+
+static void uplink_released(struct gsm_subscriber_connection *conn)
+{
+ LOG_CHAN(conn, LOGL_DEBUG, "Uplink is now released.\n");
+ /* Go into blocked or free state. */
+ if (conn->vgcs_chan.call && conn->vgcs_chan.call->vgcs_call.fi
+ && conn->vgcs_chan.call->vgcs_call.fi->state == VGCS_CALL_ST_IDLE)
+ osmo_fsm_inst_state_chg(conn->vgcs_chan.fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ else
+ osmo_fsm_inst_state_chg(conn->vgcs_chan.fi, VGCS_CHAN_ST_ACTIVE_BLOCKED, 0, 0);
+}
+
+static void vgcs_chan_fsm_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+ struct lchan_activate_info info;
+
+ switch (event) {
+ case VGCS_EV_ASSIGN_REQ:
+ LOG_CHAN(conn, LOGL_DEBUG, "MSC assigns channel.\n");
+ /* MSC requests channel assignment. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_WAIT_EST, 0, 0);
+ /* Requesting channel from BTS. */
+ info = (struct lchan_activate_info){
+ .activ_for = ACTIVATE_FOR_VGCS_CHANNEL,
+ .for_conn = conn,
+ .chreq_reason = GSM_CHREQ_REASON_OTHER,
+ .ch_mode_rate = conn->vgcs_chan.ch_mode_rate,
+ .ch_indctr = conn->vgcs_chan.ct.ch_indctr,
+ /* TSC is used from TS config. */
+ .encr = conn->vgcs_chan.new_lchan->encr,
+ /* Timing advance of 0 is used until channel is activated for uplink. */
+ .ta_known = true,
+ .ta = 0,
+ };
+ if (conn->vgcs_chan.call->vgcs_call.sf == GSM0808_SF_VGCS)
+ info.vgcs = 1;
+ else
+ info.vbs = 1;
+ /* Activate lchan. If an error occurs, this the function call may trigger VGCS_EV_LCHAN_ERROR event.
+ * This means that this must be the last action in this handler. */
+ lchan_activate(conn->vgcs_chan.new_lchan, &info);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_wait_est(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+ const struct mgcp_conn_peer *mgw_info;
+
+ switch (event) {
+ case VGCS_EV_LCHAN_ACTIVE:
+ LOG_CHAN(conn, LOGL_DEBUG, "lchan is active.\n");
+ /* If no MGW is used. */
+ if (!gscon_is_aoip(conn)) {
+ LOG_CHAN(conn, LOGL_DEBUG, "Not connecting MGW endpoint, no AoIP connection.\n");
+ goto no_aoip;
+ }
+ /* Send activation to MGW. */
+ LOG_CHAN(conn, LOGL_DEBUG, "Connecting MGW endpoint to the MSC's RTP port: %s:%u\n",
+ conn->vgcs_chan.msc_rtp_addr, conn->vgcs_chan.msc_rtp_port);
+ /* Connect MGW. The function call may trigger VGCS_EV_MGW_OK event.
+ * This means that this must be the last action in this handler.
+ * If this function fails, VGCS_EV_MGW_FAIL will not trigger. */
+ if (!gscon_connect_mgw_to_msc(conn,
+ conn->vgcs_chan.new_lchan,
+ conn->vgcs_chan.msc_rtp_addr,
+ conn->vgcs_chan.msc_rtp_port,
+ fi,
+ VGCS_EV_MGW_OK,
+ VGCS_EV_MGW_FAIL,
+ NULL,
+ NULL)) {
+ /* Report failure to MSC. */
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ break;
+ }
+ break;
+ case VGCS_EV_LCHAN_ERROR:
+ LOG_CHAN(conn, LOGL_DEBUG, "lchan failed.\n");
+ /* BTS reports failure on channel request. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_NULL, 0, 0);
+ /* Report failure to MSC. */
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ break;
+ case VGCS_EV_MGW_OK:
+ LOG_CHAN(conn, LOGL_DEBUG, "MGW endpoint connected.\n");
+ /* MGW reports success. */
+ mgw_info = osmo_mgcpc_ep_ci_get_rtp_info(conn->user_plane.mgw_endpoint_ci_msc);
+ if (!mgw_info) {
+ LOG_CHAN(conn, LOGL_ERROR, "Unable to retrieve RTP port info allocated by MGW for"
+ " the MSC side.");
+ /* Report failure to MSC. */
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ break;
+ }
+ LOG_CHAN(conn, LOGL_DEBUG, "MGW's MSC side CI: %s:%u\n", mgw_info->addr, mgw_info->port);
+no_aoip:
+ /* Channel established from BTS. */
+ gscon_change_primary_lchan(conn, conn->vgcs_chan.new_lchan);
+ /* Change state according to call state. */
+ if (conn->vgcs_chan.call && conn->vgcs_chan.call->vgcs_call.fi
+ && conn->vgcs_chan.call->vgcs_call.fi->state == VGCS_CALL_ST_IDLE)
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ else
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_BLOCKED, 0, 0);
+ /* Add call to notification channel. */
+ if (conn->vgcs_chan.call)
+ rsl_notification_cmd(conn->lchan->ts->trx->bts, conn->lchan, &conn->vgcs_chan.gc_ie, NULL);
+ /* Report result to MSC. */
+ bsc_tx_vgcs_vbs_assignment_result(conn, &conn->vgcs_chan.ct, &conn->vgcs_chan.ci,
+ conn->vgcs_chan.call_id);
+ break;
+ case VGCS_EV_MGW_FAIL:
+ LOG_CHAN(conn, LOGL_DEBUG, "MGW endpoint failed.\n");
+ /* MGW reports failure. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_NULL, 0, 0);
+ /* Report failure to MSC. */
+ bsc_tx_vgcs_vbs_assignment_fail(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ case VGCS_EV_BLOCK:
+ case VGCS_EV_UNBLOCK:
+ /* Ignore, because channel is not yet ready. */
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_active_blocked(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv, *cc;
+
+ switch (event) {
+ case VGCS_EV_UNBLOCK:
+ LOG_CHAN(conn, LOGL_DEBUG, "Unblocking channel.\n");
+ /* No uplink is used in other cell. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ break;
+ case VGCS_EV_TALKER_DET:
+ LOG_CHAN(conn, LOGL_DEBUG, "Talker detected on blocked channel.\n");
+ if (conn->vgcs_chan.call->vgcs_call.sf == GSM0808_SF_VBS)
+ LOG_CHAN(conn, LOGL_ERROR, "Talker detection not allowed on VBS channel.\n");
+ /* Race condition: BTS detected a talker. Waiting for talker to establish or fail. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_REL, 0, 0);
+ break;
+ case VGCS_EV_TALKER_EST:
+ cc = find_calling_subscr_conn(conn);
+ if (!cc) {
+ LOG_CHAN(conn, LOGL_ERROR, "No assignment requested from MSC!\n");
+ /* Uplink is used while blocked. Waiting for channel to be release. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_REL, 0, 0);
+ /* Send UPLINK RELEASE to MS. */
+ gsm48_send_uplink_release(conn->lchan, GSM48_RR_CAUSE_NORMAL);
+ /* Go into blocked or free state. */
+ uplink_released(conn);
+ break;
+ }
+ /* Talker is assigning to this channel. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_EST, 0, 0);
+ /* Report talker detection to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_CALLING_ASSIGNED, conn);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_enter_active_free(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ /* Send UPLINK FREE message to BTS. This hits on every state change (and or timer start). */
+ LOG_CHAN(conn, LOGL_DEBUG, "Sending UPLINK FREE message to channel.\n");
+ gsm48_send_uplink_free(conn->lchan, 0, NULL);
+}
+
+static void vgcs_chan_fsm_active_free(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ switch (event) {
+ case VGCS_EV_BLOCK:
+ LOG_CHAN(conn, LOGL_DEBUG, "Blocking channel.\n");
+ /* Uplink is used in other cell. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_BLOCKED, 0, 0);
+ /* Send UPLINK BUSY to MS. */
+ LOG_CHAN(conn, LOGL_DEBUG, "Sending UPLINK BUSY message to channel.\n");
+ gsm48_send_uplink_busy(conn->lchan);
+ break;
+ case VGCS_EV_TALKER_DET:
+ LOG_CHAN(conn, LOGL_DEBUG, "Talker detected on free channel.\n");
+ /* BTS detected a talker. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_INIT, 0, 0);
+ /* Report talker detection to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_DET, data);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_active_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+ uint8_t cause = (data) ? *(uint8_t *)data : 0;
+
+ switch (event) {
+ case VGCS_EV_BLOCK:
+ case VGCS_EV_REJECT:
+ LOG_CHAN(conn, LOGL_DEBUG, "Blocking/rejecting channel.\n");
+ /* Uplink is used in other cell. Waiting for channel to be established and then released. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_REL, 0, 0);
+ break;
+ case VGCS_EV_TALKER_EST:
+ LOG_CHAN(conn, LOGL_DEBUG, "Talker established uplink.\n");
+ /* Uplink has been established */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_EST, 0, 0);
+ /* Report talker establishment to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_EST, data);
+ break;
+ case VGCS_EV_TALKER_FAIL:
+ LOG_CHAN(conn, LOGL_NOTICE, "Uplink failed, establishment timeout.\n");
+ /* Release datalink */
+ rsl_release_request(conn->lchan, 0, RSL_REL_LOCAL_END);
+ /* fall thru */
+ case VGCS_EV_TALKER_REL:
+ LOG_CHAN(conn, LOGL_DEBUG, "Uplink is now released.\n");
+ /* Uplink establishment failed. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ /* Report release indication to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_REL, &cause);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_active_est(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+ uint8_t cause = (data) ? *(uint8_t *)data : 0;
+ struct msgb *msg = data;
+
+ switch (event) {
+ case VGCS_EV_BLOCK:
+ case VGCS_EV_REJECT:
+ LOG_CHAN(conn, LOGL_DEBUG, "Blocking/rejecting channel.\n");
+ /* Uplink is used in other cell. Waiting for channel to be release. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_REL, 0, 0);
+ /* Send UPLINK RELEASE to MS. */
+ gsm48_send_uplink_release(conn->lchan, GSM48_RR_CAUSE_NORMAL);
+ /* Go into blocked or free state. */
+ uplink_released(conn);
+ break;
+ case VGCS_EV_TALKER_DATA:
+ LOG_CHAN(conn, LOGL_DEBUG, "Talker sends data on uplink.\n");
+ if (msg) {
+ struct gsm48_hdr *gh;
+ uint8_t pdisc;
+ uint8_t msg_type;
+ if (msgb_l3len(msg) < sizeof(*gh)) {
+ LOG_LCHAN(msg->lchan, LOGL_ERROR,
+ "Message too short for a GSM48 header (%u)\n", msgb_l3len(msg));
+ break;
+ }
+ gh = msgb_l3(msg);
+ pdisc = gsm48_hdr_pdisc(gh);
+ msg_type = gsm48_hdr_msg_type(gh);
+ if (pdisc == GSM48_PDISC_RR && msg_type == GSM48_MT_RR_UPLINK_RELEASE) {
+ LOG_CHAN(conn, LOGL_DEBUG, "Uplink is released by UPLINK RELEASE message.\n");
+ /* Release datalink */
+ rsl_release_request(conn->lchan, 0, RSL_REL_LOCAL_END);
+ /* Talker released the uplink. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ /* Report talker release to call state machine. */
+ if (conn->vgcs_chan.call) {
+ cause = GSM0808_CAUSE_CALL_CONTROL;
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_REL,
+ &cause);
+ }
+ break;
+ }
+ if (pdisc == GSM48_PDISC_RR && msg_type == GSM48_MT_RR_ASS_COMPL) {
+ LOG_CHAN(conn, LOGL_DEBUG, "Asssignment complete.\n");
+ struct gsm_subscriber_connection *cc;
+ cc = find_calling_subscr_conn(conn);
+ if (!cc) {
+ LOG_CHAN(conn, LOGL_ERROR, "No assignment requested from MSC!\n");
+ break;
+ }
+ LOG_CHAN(conn, LOGL_DEBUG, "Trigger State machine.\n");
+ osmo_fsm_inst_dispatch(cc->assignment.fi, ASSIGNMENT_EV_RR_ASSIGNMENT_COMPLETE, msg);
+ break;
+ }
+ }
+ /* Report talker data to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_DATA, data);
+ break;
+ case VGCS_EV_MSC_DTAP:
+ LOG_CHAN(conn, LOGL_DEBUG, "MSC sends DTAP message to talker.\n");
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MT_DTAP, data);
+ break;
+ case VGCS_EV_TALKER_FAIL:
+ LOG_CHAN(conn, LOGL_NOTICE, "Uplink failed after establishment.\n");
+ /* Release datalink */
+ rsl_release_request(conn->lchan, 0, RSL_REL_LOCAL_END);
+ /* fall thru */
+ case VGCS_EV_TALKER_REL:
+ LOG_CHAN(conn, LOGL_DEBUG, "Uplink is now released.\n");
+ /* Talker released the uplink. */
+ osmo_fsm_inst_state_chg(fi, VGCS_CHAN_ST_ACTIVE_FREE, 0, 0);
+ /* Report talker release to call state machine. */
+ if (conn->vgcs_chan.call)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.call->vgcs_call.fi, VGCS_EV_TALKER_REL, &cause);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static void vgcs_chan_fsm_active_rel(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+
+ switch (event) {
+ case VGCS_EV_BLOCK:
+ case VGCS_EV_REJECT:
+ LOG_CHAN(conn, LOGL_DEBUG, "Blocking/rejecting channel.\n");
+ /* Race condition: Uplink is used in other cell, we are already releasing. */
+ break;
+ case VGCS_EV_TALKER_EST:
+ LOG_CHAN(conn, LOGL_DEBUG, "Talker established uplink, releasing.\n");
+ /* Finally the talker established the connection. Send UPLINK RELEASE to MS. */
+ gsm48_send_uplink_release(conn->lchan, GSM48_RR_CAUSE_NORMAL);
+ /* Release datalink */
+ rsl_release_request(conn->lchan, 0, RSL_REL_LOCAL_END);
+ /* fall thru */
+ case VGCS_EV_TALKER_FAIL:
+ /* Release datalink */
+ rsl_release_request(conn->lchan, 0, RSL_REL_LOCAL_END);
+ /* fall thru */
+ case VGCS_EV_TALKER_REL:
+ /* Go into blocked or free state. */
+ uplink_released(conn);
+ break;
+ case VGCS_EV_CLEANUP:
+ LOG_CHAN(conn, LOGL_DEBUG, "SCCP connection clearing.\n");
+ /* MSC wants to terminate. */
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ break;
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+static const struct osmo_fsm_state vgcs_chan_fsm_states[] = {
+ [VGCS_CHAN_ST_NULL] = {
+ .name = "NULL",
+ .in_event_mask = S(VGCS_EV_ASSIGN_REQ),
+ .out_state_mask = S(VGCS_CHAN_ST_WAIT_EST),
+ .action = vgcs_chan_fsm_null,
+ },
+ [VGCS_CHAN_ST_WAIT_EST] = {
+ .name = "WAIT_EST",
+ .in_event_mask = S(VGCS_EV_LCHAN_ACTIVE) |
+ S(VGCS_EV_LCHAN_ERROR) |
+ S(VGCS_EV_MGW_OK) |
+ S(VGCS_EV_MGW_FAIL) |
+ S(VGCS_EV_CLEANUP) |
+ S(VGCS_EV_BLOCK) |
+ S(VGCS_EV_UNBLOCK),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_BLOCKED) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE),
+ .action = vgcs_chan_fsm_wait_est,
+ },
+ [VGCS_CHAN_ST_ACTIVE_BLOCKED] = {
+ .name = "ACTIVE/BLOCKED",
+ .in_event_mask = S(VGCS_EV_UNBLOCK) |
+ S(VGCS_EV_TALKER_DET) |
+ S(VGCS_EV_TALKER_EST) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_EST) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE) |
+ S(VGCS_CHAN_ST_ACTIVE_REL),
+ .action = vgcs_chan_fsm_active_blocked,
+ },
+ [VGCS_CHAN_ST_ACTIVE_FREE] = {
+ .name = "ACTIVE/FREE",
+ .in_event_mask = S(VGCS_EV_BLOCK) |
+ S(VGCS_EV_TALKER_DET) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_BLOCKED) |
+ S(VGCS_CHAN_ST_ACTIVE_INIT) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE),
+ .action = vgcs_chan_fsm_active_free,
+ .onenter = vgcs_chan_fsm_enter_active_free,
+ },
+ [VGCS_CHAN_ST_ACTIVE_INIT] = {
+ .name = "ACTIVE/INIT",
+ .in_event_mask = S(VGCS_EV_BLOCK) |
+ S(VGCS_EV_REJECT) |
+ S(VGCS_EV_TALKER_EST) |
+ S(VGCS_EV_TALKER_FAIL) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_EST) |
+ S(VGCS_CHAN_ST_ACTIVE_REL) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE),
+ .action = vgcs_chan_fsm_active_init,
+ },
+ [VGCS_CHAN_ST_ACTIVE_EST] = {
+ .name = "ACTIVE/ESTABLISHED",
+ .in_event_mask = S(VGCS_EV_BLOCK) |
+ S(VGCS_EV_REJECT) |
+ S(VGCS_EV_TALKER_DATA) |
+ S(VGCS_EV_MSC_DTAP) |
+ S(VGCS_EV_TALKER_REL) |
+ S(VGCS_EV_TALKER_FAIL) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE) |
+ S(VGCS_CHAN_ST_ACTIVE_REL),
+ .action = vgcs_chan_fsm_active_est,
+ },
+ [VGCS_CHAN_ST_ACTIVE_REL] = {
+ .name = "ACTIVE/RELEASE",
+ .in_event_mask = S(VGCS_EV_BLOCK) |
+ S(VGCS_EV_REJECT) |
+ S(VGCS_EV_TALKER_EST) |
+ S(VGCS_EV_TALKER_REL) |
+ S(VGCS_EV_TALKER_FAIL) |
+ S(VGCS_EV_CLEANUP),
+ .out_state_mask = S(VGCS_CHAN_ST_NULL) |
+ S(VGCS_CHAN_ST_ACTIVE_BLOCKED) |
+ S(VGCS_CHAN_ST_ACTIVE_FREE),
+ .action = vgcs_chan_fsm_active_rel,
+ },
+};
+
+static struct osmo_fsm vgcs_chan_fsm = {
+ .name = "vgcs_chan",
+ .states = vgcs_chan_fsm_states,
+ .num_states = ARRAY_SIZE(vgcs_chan_fsm_states),
+ .log_subsys = DASCI,
+ .event_names = vgcs_fsm_event_names,
+ .cleanup = vgcs_chan_detach_and_destroy,
+};
+
+/* Handle VGCS/VBS ASSIGNMENT REQUEST message.
+ *
+ * See 3GPP TS 48.008 §3.2.1.53
+ */
+int vgcs_vbs_chan_start(struct gsm_subscriber_connection *conn, struct msgb *msg)
+{
+ int payload_length = msg->tail - msg->l4h;
+ struct tlv_parsed tp;
+ struct gsm_subscriber_connection *c;
+ struct gsm0808_group_callref *gc = &conn->vgcs_chan.gc_ie;
+ struct assignment_request req = {
+ .aoip = gscon_is_aoip(conn),
+ };
+ uint8_t cause;
+ struct gsm_bts *bts;
+ struct gsm_lchan *lchan;
+ int rc;
+ int i;
+
+ if (osmo_bssap_tlv_parse(&tp, msg->l4h + 1, payload_length - 1) < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;
+ goto reject;
+ }
+
+ /* Check for mandatory IEs. */
+ if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)
+ || !TLVP_PRESENT(&tp, GSM0808_IE_ASSIGNMENT_REQUIREMENT)
+ || !TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)
+ || !TLVP_PRESENT(&tp, GSM0808_IE_GROUP_CALL_REFERENCE)) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Mandatory IE not present.\n");
+ cause = GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING;
+ goto reject;
+ }
+
+ /* Decode Channel Type element. */
+ rc = gsm0808_dec_channel_type(&conn->vgcs_chan.ct, TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE),
+ TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
+ if (rc < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Unable to decode Channel Type.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+
+ /* Only speech is supported. */
+ if (conn->vgcs_chan.ct.ch_indctr != GSM0808_CHAN_SPEECH) {
+ cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;
+ goto reject;
+ }
+
+ /* Decode Assignment Requirement element. */
+ rc = gsm0808_dec_assign_req(&conn->vgcs_chan.ar, TLVP_VAL(&tp, GSM0808_IE_ASSIGNMENT_REQUIREMENT),
+ TLVP_LEN(&tp, GSM0808_IE_ASSIGNMENT_REQUIREMENT));
+ if (rc < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Unable to decode Assignment Requirement.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+
+ /* Decode Cell Identifier element. */
+ rc = gsm0808_dec_cell_id(&conn->vgcs_chan.ci, TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER),
+ TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER));
+ if (rc < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Unable to decode Cell Identifier.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ gsm0808_cell_id_u_name(conn->vgcs_chan.ci_str, sizeof(conn->vgcs_chan.ci_str), conn->vgcs_chan.ci.id_discr,
+ &conn->vgcs_chan.ci.id);
+
+ /* Decode Group Call Reference element. */
+ rc = gsm0808_dec_group_callref(gc, TLVP_VAL(&tp, GSM0808_IE_GROUP_CALL_REFERENCE),
+ TLVP_LEN(&tp, GSM0808_IE_GROUP_CALL_REFERENCE));
+ if (rc < 0) {
+ LOGPFSML(conn->fi, LOGL_ERROR, "Unable to decode Group Call Reference.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ conn->vgcs_chan.sf = gc->sf;
+ conn->vgcs_chan.call_ref = (osmo_load32be_ext_2(gc->call_ref_hi, 3) << 3) | gc->call_ref_lo;
+
+ /* Find BTS from Cell Identity. */
+ bts = gsm_bts_by_cell_id(conn->network, &conn->vgcs_chan.ci, 0);
+ if (!bts) {
+ LOG_CHAN(conn, LOGL_ERROR, "No cell found that matches the given Cell Identifier.\n");
+ cause = GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE;
+ goto reject;
+ }
+
+ /* If Cell Identity is ambiguous. */
+ if (gsm_bts_by_cell_id(conn->network, &conn->vgcs_chan.ci, 1))
+ LOG_CHAN(conn, LOGL_NOTICE, "More thant one cell found that match the given Cell Identifier.\n");
+
+ /* Decode channel related elements.
+ * This must be done after selecting the BTS, because codec selection requires relation to BTS. */
+ rc = bssmap_handle_ass_req_ct_speech(conn, bts, &tp, &conn->vgcs_chan.ct, &req, &cause);
+ if (rc < 0)
+ goto reject;
+
+ /* Store AoIP elements. */
+ osmo_strlcpy(conn->vgcs_chan.msc_rtp_addr, req.msc_rtp_addr, sizeof(conn->vgcs_chan.msc_rtp_addr));
+ conn->vgcs_chan.msc_rtp_port = req.msc_rtp_port;
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CALL_ID)) {
+ /* Decode Call Identifier element. */
+ rc = gsm0808_dec_call_id(&conn->vgcs_chan.call_id, TLVP_VAL(&tp, GSM0808_IE_CALL_ID),
+ TLVP_LEN(&tp, GSM0808_IE_CALL_ID));
+ if (rc < 0) {
+ LOG_CHAN(conn, LOGL_ERROR, "Unable to decode Call Identifier.\n");
+ cause = GSM0808_CAUSE_INCORRECT_VALUE;
+ goto reject;
+ }
+ }
+
+ /* Try to allocate a new lchan in order of preference. */
+ for (i = 0; i < req.n_ch_mode_rate; i++) {
+ lchan = lchan_select_by_chan_mode(bts,
+ req.ch_mode_rate_list[i].chan_mode,
+ req.ch_mode_rate_list[i].chan_rate,
+ SELECT_FOR_VGCS, NULL);
+ if (!lchan)
+ continue;
+ LOG_CHAN(conn, LOGL_DEBUG, "Selected new lchan %s for mode[%d] = %s channel_rate=%d\n",
+ gsm_lchan_name(lchan), i, gsm48_chan_mode_name(req.ch_mode_rate_list[i].chan_mode),
+ req.ch_mode_rate_list[i].chan_rate);
+
+ conn->vgcs_chan.ch_mode_rate = req.ch_mode_rate_list[i];
+ break;
+ }
+ if (!lchan) {
+ LOG_CHAN(conn, LOGL_ERROR, "Requested lchan not available.\n");
+ cause = GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE;
+ goto reject;
+ }
+ conn->vgcs_chan.new_lchan = lchan;
+
+ /* Create VGCS FSM. */
+ conn->vgcs_chan.fi = osmo_fsm_inst_alloc(&vgcs_chan_fsm, conn->network, conn, LOGL_DEBUG, NULL);
+ if (!conn->vgcs_chan.fi)
+ goto reject;
+
+ /* Attach to call control instance, if a call with same callref exists. */
+ llist_for_each_entry(c, &conn->network->subscr_conns, entry) {
+ if (!c->vgcs_call.fi)
+ continue;
+ if (c->vgcs_call.sf == conn->vgcs_chan.sf
+ && c->vgcs_call.call_ref == conn->vgcs_chan.call_ref) {
+ llist_add_tail(&conn->vgcs_chan.list, &c->vgcs_call.chan_list);
+ conn->vgcs_chan.call = c;
+ break;
+ }
+ }
+ if (!conn->vgcs_chan.call) {
+ LOG_CHAN(conn, LOGL_ERROR, "A %s call with callref %s does not exist.\n",
+ (conn->vgcs_chan.sf == GSM0808_SF_VGCS) ? "VGCS" : "VBS",
+ gsm44068_group_id_string(conn->vgcs_chan.call_ref));
+ cause = GSM0808_CAUSE_VGCS_VBS_CALL_NON_EXISTENT;
+ osmo_fsm_inst_term(conn->vgcs_chan.fi, 0, NULL);
+ goto reject;
+ }
+
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.fi, VGCS_EV_ASSIGN_REQ, NULL);
+ return 0;
+reject:
+ bsc_tx_vgcs_vbs_assignment_fail(conn, cause);
+ return -EINVAL;
+}
+
+/* Return lchan of group call that exists in the same BTS. */
+struct gsm_lchan *vgcs_vbs_find_lchan(struct gsm_bts *bts, struct gsm0808_group_callref *gc)
+{
+ struct gsm_subscriber_connection *call = NULL, *c;
+ struct gsm_lchan *lchan = NULL;
+ uint32_t call_ref = (osmo_load32be_ext_2(gc->call_ref_hi, 3) << 3) | gc->call_ref_lo;
+
+ /* Find group call. */
+ llist_for_each_entry(c, &bts->network->subscr_conns, entry) {
+ if (!c->vgcs_call.fi)
+ continue;
+ if (c->vgcs_call.sf == gc->sf
+ && c->vgcs_call.call_ref == call_ref) {
+ call = c;
+ break;
+ }
+ }
+ if (!call) {
+ LOGP(DASCI, LOGL_ERROR, "Cannot assign to channel, %s channel with callref %s does not exist.\n",
+ (gc->sf == GSM0808_SF_VGCS) ? "VGCS" : "VBS", gsm44068_group_id_string(call_ref));
+ return NULL;
+ }
+
+ /* Find channel in same BTS. */
+ llist_for_each_entry(c, &call->vgcs_call.chan_list, vgcs_chan.list) {
+ if (c->lchan && c->lchan->ts->trx->bts == bts)
+ lchan = c->lchan;
+ }
+ if (!call) {
+ LOGP(DASCI, LOGL_ERROR, "Cannot assign to channel, caller's BTS has no %s channel with callref %s.\n",
+ (gc->sf == GSM0808_SF_VGCS) ? "VGCS" : "VBS", gsm44068_group_id_string(call_ref));
+ return NULL;
+ }
+
+ return lchan;
+}
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33611
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Id9e94fb4f27bb438b7093c031344a3400bfa34f1
Gerrit-Change-Number: 33611
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33613 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Forward RLL to VGCS FSM
......................................................................
ASCI: Forward RLL to VGCS FSM
RLL events are forwarded to VGCS FSM. Included L3 information are not
forwarded to gsm0408_rcvmsg(), but forwarded to VGCS FSM only.
Change-Id: I5e098a20225ba11206f43281f4da519a4086bae5
Related: OS#4852
---
M src/osmo-bsc/abis_rsl.c
1 file changed, 53 insertions(+), 0 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 99c2822..ad288ab 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -58,6 +58,7 @@
#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)
@@ -1303,6 +1304,15 @@
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. */
@@ -2552,6 +2562,13 @@
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;
}
@@ -2579,9 +2596,17 @@
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(*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;
@@ -2621,6 +2646,13 @@
msg->lchan->sapis[sapi] = LCHAN_SAPI_MS;
osmo_fsm_inst_dispatch(msg->lchan->fi, LCHAN_EV_RLL_ESTABLISH_IND, msg);
+ /* 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];
@@ -2636,6 +2668,14 @@
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,
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33613
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I5e098a20225ba11206f43281f4da519a4086bae5
Gerrit-Change-Number: 33613
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[S] Change in osmo-bsc[master]: ASCI: Indicate release of subscriber connection to VGCS FSM
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33615 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Indicate release of subscriber connection to VGCS FSM
......................................................................
ASCI: Indicate release of subscriber connection to VGCS FSM
If an SCCP connection or channel is released or fails, send indications
towards VGCS FSM, so that it can terminate the state machines belonging
to these connections.
Change-Id: Ia74db9ba47fea11b359ac01269f714482485d464
Related: OS#4852
---
M src/osmo-bsc/bsc_subscr_conn_fsm.c
1 file changed, 39 insertions(+), 0 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index d9abf10..f1f48bc 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -213,6 +213,12 @@
if (conn->lcs.loc_req)
osmo_fsm_inst_dispatch(conn->lcs.loc_req->fi, LCS_LOC_REQ_EV_CONN_CLEAR, NULL);
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_CLEANUP, NULL);
+
+ if (conn->vgcs_chan.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.fi, VGCS_EV_CLEANUP, NULL);
+
gscon_release_lchans(conn, true, bsc_gsm48_rr_cause_from_gsm0808_cause(conn->clear_cause));
osmo_mgcpc_ep_clear(conn->user_plane.mgw_endpoint);
@@ -247,6 +253,8 @@
conn->lchan = NULL;
if (conn->ho.fi && conn->ho.new_lchan == lchan)
conn->ho.new_lchan = NULL;
+ if (conn->vgcs_chan.new_lchan == lchan)
+ conn->vgcs_chan.new_lchan = NULL;
if (conn->assignment.new_lchan == lchan)
conn->assignment.new_lchan = NULL;
lchan_release(lchan, do_rr_release, err, cause_rr,
@@ -953,6 +961,10 @@
if (conn->ho.fi)
osmo_fsm_inst_dispatch(conn->ho.fi, HO_EV_LCHAN_ERROR, lchan);
}
+ if (conn->vgcs_chan.new_lchan == lchan) {
+ if (conn->vgcs_chan.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.fi, VGCS_EV_LCHAN_ERROR, lchan);
+ }
if (conn->lchan == lchan) {
lchan_forget_conn(conn->lchan);
conn->lchan = NULL;
@@ -989,6 +1001,10 @@
conn->ho.new_lchan = NULL;
detach_label = "ho.new_lchan";
}
+ if (conn->vgcs_chan.new_lchan == lchan) {
+ conn->vgcs_chan.new_lchan = NULL;
+ detach_label = "vgcs.new_lchan";
+ }
if (conn->lchan == lchan) {
conn->lchan = NULL;
detach_label = "primary lchan";
@@ -1007,6 +1023,7 @@
if (!conn->lchan
&& !conn->ho.new_lchan
&& !conn->assignment.new_lchan
+ && !conn->vgcs_chan.new_lchan
&& !conn->lcs.loc_req)
gscon_bssmap_clear(conn, GSM0808_CAUSE_EQUIPMENT_FAILURE);
}
@@ -1028,6 +1045,7 @@
conn->ho.created_ci_for_msc = NULL;
lchan_forget_mgw_endpoint(conn->lchan);
lchan_forget_mgw_endpoint(conn->assignment.new_lchan);
+ lchan_forget_mgw_endpoint(conn->vgcs_chan.new_lchan);
lchan_forget_mgw_endpoint(conn->ho.new_lchan);
}
@@ -1117,6 +1135,7 @@
lchan_forget_conn(conn->lchan);
lchan_forget_conn(conn->assignment.new_lchan);
+ lchan_forget_conn(conn->vgcs_chan.new_lchan);
lchan_forget_conn(conn->ho.new_lchan);
lb_close_conn(conn);
@@ -1169,6 +1188,12 @@
conn->lcls.fi = NULL;
}
+ if (conn->vgcs_call.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_call.fi, VGCS_EV_CLEANUP, NULL);
+
+ if (conn->vgcs_chan.fi)
+ osmo_fsm_inst_dispatch(conn->vgcs_chan.fi, VGCS_EV_CLEANUP, NULL);
+
LOGPFSML(fi, LOGL_DEBUG, "Releasing all lchans (if any) because this conn is terminating\n");
gscon_release_lchans(conn, true, bsc_gsm48_rr_cause_from_gsm0808_cause(conn->clear_cause));
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33615
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Ia74db9ba47fea11b359ac01269f714482485d464
Gerrit-Change-Number: 33615
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0
[M] Change in osmo-bsc[master]: ASCI: Forward lchan activation states to VGCS FSM
by pespin 25 Jul '23
by pespin 25 Jul '23
25 Jul '23
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/33614 )
(
4 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: ASCI: Forward lchan activation states to VGCS FSM
......................................................................
ASCI: Forward lchan activation states to VGCS FSM
Change-Id: I757b562e02480c1a68446d91217910069f17d060
Related: OS#4852
---
M src/osmo-bsc/lchan_fsm.c
1 file changed, 67 insertions(+), 0 deletions(-)
Approvals:
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 12d980a..70fb811 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -43,6 +43,7 @@
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/bsc_stats.h>
#include <osmocom/bsc/lchan.h>
+#include <osmocom/bsc/vgcs_fsm.h>
static struct osmo_fsm lchan_fsm;
@@ -191,6 +192,23 @@
_osmo_fsm_inst_dispatch(for_conn->ho.fi, HO_EV_LCHAN_ERROR, lchan, file, line);
break;
+ case ACTIVATE_FOR_VGCS_CHANNEL:
+ LOG_LCHAN(lchan, LOGL_NOTICE, "Signalling VGCS Assignment FSM of error (%s)\n",
+ lchan->last_error ? : "unknown error");
+ if (!for_conn) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "lchan activation for VGCS Assignment failed, but activation request has no conn\n");
+ break;
+ }
+ if (!for_conn->vgcs_chan.fi) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "lchan activation for VGCS Assignment failed, but conn has no ongoing"
+ " assignment procedure\n");
+ break;
+ }
+ _osmo_fsm_inst_dispatch(for_conn->vgcs_chan.fi, VGCS_EV_LCHAN_ERROR, lchan, file, line);
+ break;
+
case ACTIVATE_FOR_VTY:
LOG_LCHAN(lchan, LOGL_ERROR, "VTY user invoked lchan activation failed (%s)\n",
lchan->last_error ? : "unknown error");
@@ -278,6 +296,22 @@
* we will try to roll back a modified RTP connection. */
break;
+ case ACTIVATE_FOR_VGCS_CHANNEL:
+ if (!lchan->conn) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "lchan activation for VGCS assignment succeeded, but lchan has no conn\n");
+ lchan_release(lchan, false, true, RSL_ERR_EQUIPMENT_FAIL, NULL);
+ break;
+ }
+ if (!lchan->conn->vgcs_chan.fi) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "lchan Activation for VGCS assignment requested, but conn has no VGCS resource FSM.\n");
+ lchan_release(lchan, false, true, RSL_ERR_EQUIPMENT_FAIL, NULL);
+ break;
+ }
+ osmo_fsm_inst_dispatch(lchan->conn->vgcs_chan.fi, VGCS_EV_LCHAN_ACTIVE, lchan);
+ break;
+
case ACTIVATE_FOR_MODE_MODIFY_RTP:
lchan_on_mode_modify_success(lchan);
break;
@@ -412,6 +446,28 @@
}
break;
+ case ACTIVATE_FOR_VGCS_CHANNEL:
+ if (!info->for_conn
+ || !info->for_conn->fi) {
+ LOG_LCHAN(lchan, LOGL_ERROR, "Activation requested, but no conn\n");
+ goto abort;
+ }
+ if (!info->for_conn->vgcs_chan.fi) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "Activation for VGCS assignment requested, but conn has no VGCS resource FSM.\n");
+ goto abort;
+ }
+ if (info->for_conn->vgcs_chan.new_lchan != lchan) {
+ LOG_LCHAN(lchan, LOGL_ERROR,
+ "Activation for VGCS assignment requested, but conn's VGCS assignment state does"
+ " not reflect this lchan to be activated (instead: %s)\n",
+ info->for_conn->vgcs_chan.new_lchan ?
+ gsm_lchan_name(info->for_conn->vgcs_chan.new_lchan)
+ : "NULL");
+ goto abort;
+ }
+ break;
+
default:
break;
}
@@ -856,6 +912,7 @@
ho_ref = lchan->conn->ho.ho_ref;
break;
case ACTIVATE_FOR_ASSIGNMENT:
+ case ACTIVATE_FOR_VGCS_CHANNEL:
default:
act_type = RSL_ACT_INTRA_NORM_ASS;
break;
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/33614
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I757b562e02480c1a68446d91217910069f17d060
Gerrit-Change-Number: 33614
Gerrit-PatchSet: 8
Gerrit-Owner: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
1
0