Change in osmocom-bb[master]: layer23/mobile: implement handling of TCH test loop commands

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

fixeria gerrit-no-reply at lists.osmocom.org
Thu Jul 30 17:43:49 UTC 2020


fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmocom-bb/+/19459 )


Change subject: layer23/mobile: implement handling of TCH test loop commands
......................................................................

layer23/mobile: implement handling of TCH test loop commands

For more information, see 3GPP TS 44.014, sections:

  - 5.1 "Single-slot TCH loops", and
  - 8 "Message definitions and contents".

This feature has nothing to do with the Mobility Management, so
let's handle GSM48_PDISC_TEST messages in the Radio Resources
layer implementation (gsm48_mm.c -> gsm48_rr.c).

Change-Id: If8efc57c7017aa8ea47b37c472d1bbb1914389ca
---
M src/host/layer23/include/osmocom/bb/common/l1ctl.h
M src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
M src/host/layer23/src/common/l1ctl.c
M src/host/layer23/src/mobile/Makefile.am
A src/host/layer23/src/mobile/gsm414.c
M src/host/layer23/src/mobile/gsm48_mm.c
M src/host/layer23/src/mobile/gsm48_rr.c
7 files changed, 239 insertions(+), 15 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/59/19459/1

diff --git a/src/host/layer23/include/osmocom/bb/common/l1ctl.h b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
index e4dbded..02ffa34 100644
--- a/src/host/layer23/include/osmocom/bb/common/l1ctl.h
+++ b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
@@ -49,7 +49,7 @@
 
 /* Transmit TCH_MODE_REQ */
 int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode,
-	uint8_t audio_mode);
+			  uint8_t audio_mode, uint8_t tch_loop_mode);
 
 /* Transmit ECHO_REQ */
 int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len);
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
index 6996ff3..9b499a6 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
@@ -188,6 +188,9 @@
 	/* audio flow */
 	uint8_t                 audio_mode;
 
+	/* 3GPP TS 44.014 TCH test loop mode (L1CTL specific format) */
+	uint8_t			tch_loop_mode;
+
 	/* sapi 3 */
 	uint8_t			sapi3_state;
 	uint8_t			sapi3_link_id;
diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c
index 54c7452..a0c156f 100644
--- a/src/host/layer23/src/common/l1ctl.c
+++ b/src/host/layer23/src/common/l1ctl.c
@@ -461,7 +461,7 @@
 
 /* Transmit L1CTL_TCH_MODE_REQ */
 int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode,
-	uint8_t audio_mode)
+			  uint8_t audio_mode, uint8_t tch_loop_mode)
 {
 	struct msgb *msg;
 	struct l1ctl_tch_mode_req *req;
@@ -475,6 +475,7 @@
 	req = (struct l1ctl_tch_mode_req *) msgb_put(msg, sizeof(*req));
 	req->tch_mode = tch_mode;
 	req->audio_mode = audio_mode;
+	req->loop_mode = tch_loop_mode;
 
 	return osmo_send_l1(ms, msg);
 }
diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am
index 4e80e4e..783ae16 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -4,7 +4,7 @@
 
 noinst_LIBRARIES = libmobile.a
 libmobile_a_SOURCES = gsm322.c gsm480_ss.c gsm411_sms.c gsm48_cc.c gsm48_mm.c \
-	gsm48_rr.c mnccms.c settings.c subscriber.c support.c \
+	gsm48_rr.c gsm414.c mnccms.c settings.c subscriber.c support.c \
 	transaction.c vty_interface.c voice.c mncc_sock.c primitives.c
 
 bin_PROGRAMS = mobile
diff --git a/src/host/layer23/src/mobile/gsm414.c b/src/host/layer23/src/mobile/gsm414.c
new file mode 100644
index 0000000..2f630df
--- /dev/null
+++ b/src/host/layer23/src/mobile/gsm414.c
@@ -0,0 +1,220 @@
+/*
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy at sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/rsl.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_04_14.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/logging.h>
+
+#include <l1ctl_proto.h>
+
+int gsm48_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause);
+int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
+		   struct msgb *msg, uint8_t link_id);
+struct msgb *gsm48_l3_msgb_alloc(void);
+
+#define loop_mode_name(mode) \
+	get_value_string(loop_mode_names, mode)
+
+static const struct value_string loop_mode_names[] = {
+	{ L1CTL_TCH_LOOP_OPEN,	"(OPEN)" },
+	{ L1CTL_TCH_LOOP_A,	"A" },
+	{ L1CTL_TCH_LOOP_B,	"B" },
+	{ L1CTL_TCH_LOOP_C,	"C" },
+	{ L1CTL_TCH_LOOP_D,	"D" },
+	{ L1CTL_TCH_LOOP_E,	"E" },
+	{ L1CTL_TCH_LOOP_F,	"F" },
+	{ L1CTL_TCH_LOOP_I,	"I" },
+	{ 0, NULL }
+};
+
+static struct msgb *alloc_gsm414_msg(uint8_t msg_type)
+{
+	struct gsm48_hdr *ngh;
+	struct msgb *nmsg;
+
+	nmsg = gsm48_l3_msgb_alloc();
+	if (nmsg == NULL)
+		return NULL;
+
+	ngh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*ngh));
+	ngh->proto_discr = GSM48_PDISC_TEST;
+	ngh->msg_type = msg_type;
+
+	return nmsg;
+}
+
+static int handle_close_tch_loop(struct osmocom_ms *ms, const struct msgb *msg)
+{
+	struct gsm48_rrlayer *rr = &ms->rrlayer;
+	const struct gsm48_hdr *gh = msgb_l3(msg);
+	unsigned int msg_len = msgb_l3len(msg);
+	struct msgb *nmsg;
+
+	/* Make sure that we have an active connection */
+	if (rr->state != GSM48_RR_ST_DEDICATED) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop requires an active connection\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	/* Make sure that the established channel is either TCH/F or TCH/H */
+	if ((rr->cd_now.chan_nr & 0xf8) != RSL_CHAN_Bm_ACCHs
+	 && (rr->cd_now.chan_nr & 0xf0) != RSL_CHAN_Lm_ACCHs) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop requires a TCH/F or TCH/H connection\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	/* Check if a loop is already closed */
+	if (rr->tch_loop_mode != L1CTL_TCH_LOOP_OPEN) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop has already been closed\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	if ((msg_len - sizeof(*gh)) < 1)
+		return -EINVAL;
+
+	/* Parse type of the TCH test loop, convert to L1CTL format */
+	uint8_t gsm414_loop_mode = (gh->data[0] >> 1) & 0x1f;
+
+	/* NOTE: some bits are not specified, so they can be 0 or 1 */
+	if (gsm414_loop_mode == GSM414_LOOP_A)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_A;
+	else if (gsm414_loop_mode == GSM414_LOOP_B)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_B;
+	else if ((gsm414_loop_mode & 0x1e) == GSM414_LOOP_C)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_C;
+	else if ((gsm414_loop_mode & 0x1c) == GSM414_LOOP_D)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_D;
+	else if ((gsm414_loop_mode & 0x1c) == GSM414_LOOP_E)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_E;
+	else if ((gsm414_loop_mode & 0x1c) == GSM414_LOOP_F)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_F;
+	else if ((gsm414_loop_mode & 0x1c) == GSM414_LOOP_I)
+		rr->tch_loop_mode = L1CTL_TCH_LOOP_I;
+	else {
+		LOGP(DMM, LOGL_NOTICE, "Unhandled 3GPP TS 44.014 TCH loop "
+		     "mode=0x%02x => rejecting\n", gsm414_loop_mode);
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N);
+		return -ENOTSUP;
+	}
+
+	LOGP(DMM, LOGL_NOTICE, "(%s) Closing 3GPP TS 44.014 TCH loop mode '%s'\n",
+	     rsl_chan_nr_str(rr->cd_now.chan_nr), loop_mode_name(rr->tch_loop_mode));
+
+	/* Instruct the L1 to enable received TCH loopback mode
+	 * FIXME: delay applying this mode, so we can send the ACK first */
+	l1ctl_tx_tch_mode_req(ms, rr->cd_now.mode, rr->audio_mode, rr->tch_loop_mode);
+
+	/* Craft and send the ACKnowledgement */
+	nmsg = alloc_gsm414_msg(GSM414_MT_CLOSE_TCH_LOOP_ACK);
+	if (nmsg == NULL)
+		return -ENOMEM;
+
+	return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
+}
+
+static int handle_open_tch_loop(struct osmocom_ms *ms, const struct msgb *msg)
+{
+	struct gsm48_rrlayer *rr = &ms->rrlayer;
+	struct msgb *nmsg;
+
+	/* Make sure that we have an active connection */
+	if (rr->state != GSM48_RR_ST_DEDICATED) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop requires an active connection\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	/* Make sure that the established channel is either TCH/F or TCH/H */
+	if ((rr->cd_now.chan_nr & 0xf8) != RSL_CHAN_Bm_ACCHs
+	 && (rr->cd_now.chan_nr & 0xf0) != RSL_CHAN_Lm_ACCHs) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop requires a TCH/F or TCH/H connection\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	/* Check if a loop actually needs to be closed */
+	if (rr->tch_loop_mode == L1CTL_TCH_LOOP_OPEN) {
+		LOGP(DMM, LOGL_NOTICE, "TCH loop has not been closed (already open)\n");
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT);
+		return -EINVAL;
+	}
+
+	LOGP(DMM, LOGL_NOTICE, "(%s) Opening 3GPP TS 44.014 TCH loop mode '%s'\n",
+	     rsl_chan_nr_str(rr->cd_now.chan_nr), loop_mode_name(rr->tch_loop_mode));
+
+	/* Instruct the L1 to disable the TCH loopback mode */
+	l1ctl_tx_tch_mode_req(ms, rr->cd_now.mode, rr->audio_mode, L1CTL_TCH_LOOP_OPEN);
+
+	/* Only the loop mode C needs to be ACKnowledged */
+	bool needs_ack = rr->tch_loop_mode == L1CTL_TCH_LOOP_C;
+	rr->tch_loop_mode = L1CTL_TCH_LOOP_OPEN;
+	if (!needs_ack)
+		return 0;
+
+	/* Craft and send the ACKnowledgement */
+	nmsg = alloc_gsm414_msg(GSM414_MT_OPEN_LOOP_CMD);
+	if (nmsg == NULL)
+		return -ENOMEM;
+
+	msgb_put_u8(nmsg, GSM414_OPEN_LOOP_ACK_IE);
+
+	return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0);
+}
+
+int gsm414_rcv_test(struct osmocom_ms *ms, const struct msgb *msg)
+{
+	const struct gsm48_hdr *gh = msgb_l3(msg);
+
+	LOGP(DMM, LOGL_INFO, "Received 3GPP TS 44.014 message '%s' (0x%02x)\n",
+	     get_value_string(gsm414_msgt_names, gh->msg_type), gh->msg_type);
+
+	/* TODO: check if the test SIM (special EF.ADM) is inserted */
+	switch (gh->msg_type) {
+	case GSM414_MT_CLOSE_TCH_LOOP_CMD:
+		return handle_close_tch_loop(ms, msg);
+	case GSM414_MT_OPEN_LOOP_CMD:
+		return handle_open_tch_loop(ms, msg);
+	default:
+		LOGP(DMM, LOGL_NOTICE, "Unhandled 3GPP TS 44.014 message '%s' (0x%02x)\n",
+		     get_value_string(gsm414_msgt_names, gh->msg_type), gh->msg_type);
+		gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N);
+		return -ENOTSUP;
+	}
+}
diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c
index 52c6fe9..49cc2bc 100644
--- a/src/host/layer23/src/mobile/gsm48_mm.c
+++ b/src/host/layer23/src/mobile/gsm48_mm.c
@@ -4076,14 +4076,9 @@
 		msgb_free(msg);
 		return rc;
 
-	case GSM48_PDISC_TEST: /* test TS 04.14 */
-		LOGP(DMM, LOGL_NOTICE, "Test protocol 0x%02x according to "
-			"TS 04.14 is not supported.\n", pdisc);
-		goto status;
 	default:
 		LOGP(DMM, LOGL_NOTICE, "Protocol type 0x%02x unsupported.\n",
 			pdisc);
-status:
 		msgb_free(msg);
 		return gsm48_mm_tx_mm_status(ms,
 			GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED);
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 0449ee3..64d64f1 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -93,6 +93,7 @@
 static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
 	uint8_t mode);
 static int gsm48_rr_rel_cnf(struct osmocom_ms *ms, struct msgb *msg);
+int gsm414_rcv_test(struct osmocom_ms *ms, const struct msgb *msg);
 
 /*
  * support
@@ -516,8 +517,8 @@
 }
 
 /* push rsl header and send (RSL-SAP) */
-static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
-				struct msgb *msg, uint8_t link_id)
+int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
+		   struct msgb *msg, uint8_t link_id)
 {
 	struct gsm48_rrlayer *rr = &ms->rrlayer;
 
@@ -879,7 +880,7 @@
  */
 
 /* send rr status request */
-static int gsm48_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
+int gsm48_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
 {
 	struct msgb *nmsg;
 	struct gsm48_hdr *gh;
@@ -3433,7 +3434,7 @@
 	/* setting (new) timing advance */
 	LOGP(DRR, LOGL_INFO, "setting TCH mode to %d, audio mode to %d\n",
 		mode, rr->audio_mode);
-	l1ctl_tx_tch_mode_req(ms, mode, rr->audio_mode);
+	l1ctl_tx_tch_mode_req(ms, mode, rr->audio_mode, rr->tch_loop_mode);
 
 	return 0;
 }
@@ -4627,9 +4628,9 @@
 	struct gsm48_hdr *gh = msgb_l3(msg);
 	struct gsm48_rr_hdr *rrh;
 	uint8_t pdisc = gh->proto_discr & 0x0f;
+	int rc = -EINVAL;
 
 	if (pdisc == GSM48_PDISC_RR) {
-		int rc = -EINVAL;
 		uint8_t skip_ind = (gh->proto_discr & 0xf0) >> 4;
 
 		/* ignore if skip indicator is not B'0000' */
@@ -4676,6 +4677,10 @@
 
 		msgb_free(msg);
 		return rc;
+	} else if (pdisc == GSM48_PDISC_TEST) {
+		rc = gsm414_rcv_test(ms, msg);
+		msgb_free(msg);
+		return rc;
 	}
 
 	/* pull off RSL header up to L3 message */
@@ -5505,6 +5510,7 @@
 	start_rr_t_meas(rr, 1, 0);
 
 	rr->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+	rr->tch_loop_mode = L1CTL_TCH_LOOP_OPEN;
 
 	return 0;
 }
@@ -5707,6 +5713,5 @@
 	 && ch_type != RSL_CHAN_Lm_ACCHs)
 		return 0;
 
-	return l1ctl_tx_tch_mode_req(ms, rr->cd_now.mode, mode);
+	return l1ctl_tx_tch_mode_req(ms, rr->cd_now.mode, mode, rr->tch_loop_mode);
 }
-

-- 
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/19459
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: If8efc57c7017aa8ea47b37c472d1bbb1914389ca
Gerrit-Change-Number: 19459
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200730/753a74b6/attachment.htm>


More information about the gerrit-log mailing list