aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-bts/bts_model.h1
-rw-r--r--include/osmo-bts/handover.h2
-rw-r--r--src/common/handover.c112
-rw-r--r--src/osmo-bts-sysmo/oml.c9
-rw-r--r--tests/stubs.c2
5 files changed, 126 insertions, 0 deletions
diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h
index 2f6ae98d..cb5433b4 100644
--- a/include/osmo-bts/bts_model.h
+++ b/include/osmo-bts/bts_model.h
@@ -29,6 +29,7 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp);
int bts_model_rsl_chan_rel(struct gsm_lchan *lchan);
+int bts_model_rsl_chan_mod(struct gsm_lchan *lchan);
int bts_model_rsl_deact_sacch(struct gsm_lchan *lchan);
int bts_model_rsl_mode_modify(struct gsm_lchan *lchan);
diff --git a/include/osmo-bts/handover.h b/include/osmo-bts/handover.h
index 1cf5d696..35d5c690 100644
--- a/include/osmo-bts/handover.h
+++ b/include/osmo-bts/handover.h
@@ -6,5 +6,7 @@ enum {
HANDOVER_WAIT_FRAME,
};
+void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay);
+void handover_frame(struct gsm_lchan *lchan);
void handover_reset(struct gsm_lchan *lchan);
diff --git a/src/common/handover.c b/src/common/handover.c
index c40219db..ab3cbcf8 100644
--- a/src/common/handover.c
+++ b/src/common/handover.c
@@ -34,6 +34,118 @@
#include <osmo-bts/logging.h>
#include <osmo-bts/handover.h>
+/* Transmit a handover related PHYS INFO on given lchan */
+static int ho_tx_phys_info(struct gsm_lchan *lchan)
+{
+ struct msgb *msg = msgb_alloc_headroom(1024, 128, "PHYS INFO");
+ struct gsm48_hdr *gh;
+
+ if (!msg)
+ return -ENOMEM;
+
+ LOGP(DHO, LOGL_INFO,
+ "%s Sending PHYSICAL INFORMATION to MS.\n",
+ gsm_lchan_name(lchan));
+
+ /* Build RSL UNITDATA REQUEST message with 04.08 PHYS INFO */
+ msg->l3h = msg->data;
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_HANDO_INFO;
+ msgb_put_u8(msg, lchan->rqd_ta);
+
+ rsl_rll_push_l3(msg, RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan),
+ 0x00, 0);
+
+ lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
+ return 0;
+}
+
+/* timer call-back for T3105 (handover PHYS INFO re-transmit) */
+static void ho_t3105_cb(void *data)
+{
+ struct gsm_lchan *lchan = data;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ struct gsm_bts_role_bts *btsb = bts->role;
+
+ LOGP(DHO, LOGL_INFO, "%s T3105 timeout (%d resends left)\n",
+ gsm_lchan_name(lchan), btsb->ny1 - lchan->ho.phys_info_count);
+
+ if (lchan->state != LCHAN_S_ACTIVE) {
+ LOGP(DHO, LOGL_NOTICE,
+ "%s is in not active. It is in state %s. Ignoring\n",
+ gsm_lchan_name(lchan), gsm_lchans_name(lchan->state));
+ return;
+ }
+
+ if (lchan->ho.phys_info_count >= btsb->ny1) {
+ /* HO Abort */
+ LOGP(DHO, LOGL_NOTICE, "%s NY1 reached, sending CONNection "
+ "FAILure to BSC.\n", gsm_lchan_name(lchan));
+ rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
+ return;
+ }
+
+ ho_tx_phys_info(lchan);
+ lchan->ho.phys_info_count++;
+ osmo_timer_schedule(&lchan->ho.t3105, 0, btsb->t3105_ms * 1000);
+}
+
+/* received random access on dedicated channel */
+void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ struct gsm_bts_role_bts *btsb = bts->role;
+
+ /* Ignore invalid handover ref */
+ if (lchan->ho.ref != ra) {
+ LOGP(DHO, LOGL_INFO, "%s RACH on dedicated channel received, but "
+ "ra=0x%02x != expected ref=0x%02x. (This is no bug)\n",
+ gsm_lchan_name(lchan), ra, lchan->ho.ref);
+ return;
+ }
+
+ LOGP(DHO, LOGL_NOTICE,
+ "%s RACH on dedicated channel received with TA=%u\n",
+ gsm_lchan_name(lchan), acc_delay);
+
+ /* Set timing advance */
+ lchan->rqd_ta = acc_delay;
+
+ /* Stop handover detection, wait for valid frame */
+ lchan->ho.active = HANDOVER_WAIT_FRAME;
+ if (bts_model_rsl_chan_mod(lchan) != 0) {
+ LOGP(DHO, LOGL_ERROR,
+ "%s failed to modify channel after handover\n",
+ gsm_lchan_name(lchan));
+ rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
+ return;
+ }
+
+ /* Send HANDover DETect to BSC */
+ rsl_tx_hando_det(lchan, &lchan->rqd_ta);
+
+ /* Send PHYS INFO */
+ lchan->ho.phys_info_count = 1;
+ ho_tx_phys_info(lchan);
+
+ /* Start T3105 */
+ LOGP(DHO, LOGL_DEBUG,
+ "%s Starting T3105 with %u ms\n",
+ gsm_lchan_name(lchan), btsb->t3105_ms);
+ lchan->ho.t3105.cb = ho_t3105_cb;
+ lchan->ho.t3105.data = lchan;
+ osmo_timer_schedule(&lchan->ho.t3105, 0, btsb->t3105_ms * 1000);
+}
+
+/* received frist valid data frame on dedicated channel */
+void handover_frame(struct gsm_lchan *lchan)
+{
+ LOGP(DHO, LOGL_INFO,
+ "%s First valid frame detected\n", gsm_lchan_name(lchan));
+ handover_frame(lchan);
+}
+
/* release handover state */
void handover_reset(struct gsm_lchan *lchan)
{
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index 11222b18..53ad45ba 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -1577,6 +1577,15 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp)
return 0;
}
+/**
+ * Modify the given lchan in the handover scenario. This is a lot like
+ * second channel activation but with some additional activation.
+ */
+int bts_model_rsl_chan_mod(struct gsm_lchan *lchan)
+{
+ return -1;
+}
+
int bts_model_rsl_chan_rel(struct gsm_lchan *lchan)
{
/* A duplicate RF Release Request, ignore it */
diff --git a/tests/stubs.c b/tests/stubs.c
index c0955f3a..53aa434e 100644
--- a/tests/stubs.c
+++ b/tests/stubs.c
@@ -37,6 +37,8 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp)
{ return 0; }
int bts_model_rsl_mode_modify(struct gsm_lchan *lchan)
{ return 0; }
+int bts_model_rsl_chan_mod(struct gsm_lchan *lchan)
+{ return 0; }
void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
unsigned int rtp_pl_len) {}