aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/bsc/gsm_data.h3
-rw-r--r--src/osmo-bsc/bsc_subscr_conn_fsm.c2
-rw-r--r--src/osmo-bsc/gsm_04_08_rr.c66
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c19
4 files changed, 89 insertions, 1 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 9f2f8169f..a5fe1f1bd 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -557,6 +557,9 @@ struct gsm_lchan {
/* If a release event is being handled, ignore other ricocheting release events until that
* release handling has concluded. */
bool in_release_handler;
+
+ /* is this release at the end of a CSFB call? */
+ bool is_csfb;
} release;
/* The logical channel type */
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index fc34968e7..13a573021 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -718,6 +718,8 @@ static void gscon_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *d
/* Regular allstate event processing */
switch (event) {
case GSCON_EV_A_CLEAR_CMD:
+ if (conn->lchan)
+ conn->lchan->release.is_csfb = *(bool *)data;
/* MSC tells us to cleanly shut down */
if (conn->fi->state != ST_CLEARING)
osmo_fsm_inst_state_chg(fi, ST_CLEARING, 60, 999);
diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c
index f1061ef4d..349bfeade 100644
--- a/src/osmo-bsc/gsm_04_08_rr.c
+++ b/src/osmo-bsc/gsm_04_08_rr.c
@@ -28,7 +28,9 @@
#include <netinet/in.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/bitvec.h>
#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/sysinfo.h>
#include <osmocom/bsc/abis_rsl.h>
#include <osmocom/bsc/debug.h>
@@ -40,6 +42,8 @@
#include <osmocom/bsc/assignment_fsm.h>
#include <osmocom/bsc/handover_fsm.h>
#include <osmocom/bsc/gsm_08_08.h>
+#include <osmocom/bsc/gsm_data.h>
+
/* should ip.access BTS use direct RTP streams between each other (1),
* or should OpenBSC always act as RTP relay/proxy in between (0) ? */
@@ -236,6 +240,56 @@ static void mr_config_for_ms(struct gsm_lchan *lchan, struct msgb *msg)
lchan->mr_ms_lv + 1);
}
+
+#define CELL_SEL_IND_AFTER_REL_MAX_BITS (4+MAX_EARFCN_LIST*19)
+#define CELL_SEL_IND_AFTER_REL_MAX_BYTES ((CELL_SEL_IND_AFTER_REL_MAX_BITS/8)+1)
+
+/* Generate a CSN.1 encoded "Cell Selection Indicator after release of all TCH and SDCCH"
+ * as per TF 44.018 version 15.3.0 Table 10.5.2.1e.1. This only generates the "value"
+ * part of the IE, not the tag+length wrapper */
+static int generate_cell_sel_ind_after_rel(uint8_t *out, unsigned int out_len, const struct gsm_bts *bts)
+{
+ struct bitvec bv;
+ unsigned int i, rc;
+
+ bv.data = out;
+ bv.data_len = out_len;
+ bitvec_zero(&bv);
+
+ /* E-UTRAN Description */
+ bitvec_set_uint(&bv, 3, 3);
+ bitvec_set_bit(&bv, 1);
+
+ for (i = 0; i < MAX_EARFCN_LIST; i++) {
+ const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
+ if (e->arfcn[i] == OSMO_EARFCN_INVALID)
+ continue;
+
+ if (bitvec_tailroom_bits(&bv) < 19) {
+ LOGP(DRR, LOGL_NOTICE, "%s: Not enough room to store EARFCN %u in the "
+ "Cell Selection Indicator IE\n", gsm_bts_name(bts), e->arfcn[i]);
+ } else {
+ bitvec_set_uint(&bv, e->arfcn[i], 16);
+ /* No "Measurement Bandwidth" */
+ bitvec_set_bit(&bv, 0);
+ /* No "Not Allowed Cells" */
+ bitvec_set_bit(&bv, 0);
+ /* No "TARGET_PCID" */
+ bitvec_set_bit(&bv, 0);
+ }
+ }
+
+ rc = bitvec_used_bytes(&bv);
+
+ if (rc == 1) {
+ /* only the header was written to the bitvec, no actual EARFCNs were present */
+ return 0;
+ } else {
+ /* return the number of bytes used */
+ return rc;
+ }
+}
+
/* 7.1.7 and 9.1.7: RR CHANnel RELease */
int gsm48_send_rr_release(struct gsm_lchan *lchan)
{
@@ -250,6 +304,18 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan)
cause = msgb_put(msg, 1);
cause[0] = GSM48_RR_CAUSE_NORMAL;
+ if (lchan->release.is_csfb) {
+ uint8_t buf[CELL_SEL_IND_AFTER_REL_MAX_BYTES];
+ int len;
+
+ len = generate_cell_sel_ind_after_rel(buf, sizeof(buf), lchan->ts->trx->bts);
+ if (len == 0) {
+ LOGPLCHAN(lchan, DRR, LOGL_NOTICE, "MSC indicated CSFB Fast Return, but "
+ "BTS has no EARFCN configured!\n");
+ } else
+ msgb_tlv_put(msg, GSM48_IE_CELL_SEL_IND_AFTER_REL, len, buf);
+ }
+
DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
lchan->nr, lchan->type);
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index f2ccf2cf1..ab7f79ce1 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -420,6 +420,23 @@ static int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int ciphe
return gsm48_send_rr_ciph_mode(conn->lchan, include_imeisv);
}
+static int bssmap_handle_clear_cmd(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, unsigned int length)
+{
+ struct tlv_parsed tp;
+ bool is_csfb = false;
+
+ tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
+
+ /* FIXME: Check for mandatory cause IE, and use that in RR RELEASE cause! */
+ if (TLVP_PRESENT(&tp, GSM0808_IE_CSFB_INDICATION))
+ is_csfb = true;
+
+ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CLEAR_CMD, &is_csfb);
+
+ return 0;
+}
+
/*
* GSM 08.08 ยง 3.1.14 cipher mode handling. We will have to pick
* the cipher to be used for this. In case we are already using
@@ -867,7 +884,7 @@ static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn,
switch (msg->l4h[0]) {
case BSS_MAP_MSG_CLEAR_CMD:
- osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CLEAR_CMD, msg);
+ ret = bssmap_handle_clear_cmd(conn, msg, length);
break;
case BSS_MAP_MSG_CIPHER_MODE_CMD:
ret = bssmap_handle_cipher_mode(conn, msg, length);