aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/osmo-bts-sysmo/l1_if.c26
-rw-r--r--src/osmo-bts-sysmo/oml.c53
2 files changed, 77 insertions, 2 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 32da5d9f..bdd06f0d 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -47,6 +47,7 @@
#include <osmo-bts/paging.h>
#include <osmo-bts/measurement.h>
#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/handover.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1prim.h>
@@ -705,6 +706,9 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
data_ind->msgUnitParam.u8Size));
dump_meas_res(LOGL_DEBUG, &data_ind->measParam);
+ if (lchan->ho.active == HANDOVER_WAIT_FRAME)
+ handover_frame(lchan);
+
switch (data_ind->sapi) {
case GsmL1_Sapi_Sacch:
radio_link_timeout(lchan, (data_ind->msgUnitParam.u8Size == 0));
@@ -819,11 +823,26 @@ static int check_acc_delay(GsmL1_PhRaInd_t *ra_ind, struct gsm_bts_role_bts *bts
return *acc_delay <= btsb->max_ta;
}
+static int handle_handover(struct gsm_lchan *lchan, struct gsm_bts_role_bts *btsb,
+ GsmL1_PhRaInd_t *ra_ind)
+{
+ uint8_t acc_delay;
+ if (!check_acc_delay(ra_ind, btsb, &acc_delay)) {
+ LOGP(DHO, LOGL_INFO, "%s ignoring RACH request %u > max_ta(%u)\n",
+ gsm_lchan_name(lchan), acc_delay, btsb->max_ta);
+ return 0;
+ }
+
+ handover_rach(lchan, ra_ind->msgUnitParam.u8Buffer[0], acc_delay);
+ return 0;
+}
+
static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts->role;
+ struct gsm_lchan *lchan;
struct osmo_phsap_prim pp;
struct lapdm_channel *lc;
uint8_t acc_delay;
@@ -836,6 +855,13 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind)
if (ra_ind->measParam.fLinkQuality < fl1->min_qual_rach)
return 0;
+ /*
+ * Check if this is a handover
+ */
+ lchan = l1if_hLayer_to_lchan(trx, ra_ind->hLayer2);
+ if (lchan && lchan->ho.active == HANDOVER_ENABLED)
+ return handle_handover(lchan, btsb, ra_ind);
+
/* increment number of RACH slots with valid RACH burst */
if (trx == bts->c0)
btsb->load.rach.access++;
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index 53ad45ba..056ef5d2 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -1,5 +1,5 @@
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
- * (C) 2013 by Holger Hans Peter Freyther
+ * (C) 2013-2014 by Holger Hans Peter Freyther
*
* All Rights Reserved
*
@@ -35,6 +35,7 @@
#include <osmo-bts/amr.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/bts_model.h>
+#include <osmo-bts/handover.h>
#include "l1_if.h"
#include "femtobts.h"
@@ -460,6 +461,10 @@ static const struct sapi_dir pdtch_sapis[] = {
#endif
};
+static const struct sapi_dir ho_sapis[] = {
+ { GsmL1_Sapi_Rach, GsmL1_Dir_RxUplink },
+};
+
struct lchan_sapis {
const struct sapi_dir *sapis;
unsigned int num_sapis;
@@ -488,6 +493,11 @@ static const struct lchan_sapis sapis_for_lchan[_GSM_LCHAN_MAX] = {
},
};
+static const struct lchan_sapis sapis_for_ho = {
+ .sapis = ho_sapis,
+ .num_sapis = ARRAY_SIZE(ho_sapis),
+};
+
static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd);
@@ -939,6 +949,11 @@ int lchan_activate(struct gsm_lchan *lchan)
"%s Trying to activate lchan, but commands in queue\n",
gsm_lchan_name(lchan));
+ /* override the regular SAPIs if this is the first hand-over
+ * related activation of the LCHAN */
+ if (lchan->ho.active == HANDOVER_ENABLED)
+ s4l = &sapis_for_ho;
+
for (i = 0; i < s4l->num_sapis; i++) {
int sapi = s4l->sapis[i].sapi;
int dir = s4l->sapis[i].dir;
@@ -1370,6 +1385,18 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir)
return enqueue_sapi_deact_cmd(lchan, sapi, dir);
}
+static int release_sapis_for_ho(struct gsm_lchan *lchan)
+{
+ int res = 0;
+ int i;
+
+ const struct lchan_sapis *s4l = &sapis_for_ho;
+
+ for (i = s4l->num_sapis-1; i >= 0; i--)
+ res |= check_sapi_release(lchan,
+ s4l->sapis[i].sapi, s4l->sapis[i].dir);
+ return res;
+}
static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
{
@@ -1389,6 +1416,9 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan)
res |= check_sapi_release(lchan, s4l->sapis[i].sapi, s4l->sapis[i].dir);
}
+ /* always attempt to disable the RACH burst */
+ res |= release_sapis_for_ho(lchan);
+
/* nothing was queued */
if (res == 0) {
LOGP(DL1C, LOGL_ERROR, "%s all SAPIs already released?\n",
@@ -1583,7 +1613,26 @@ int bts_model_rsl_chan_act(struct gsm_lchan *lchan, struct tlv_parsed *tp)
*/
int bts_model_rsl_chan_mod(struct gsm_lchan *lchan)
{
- return -1;
+ const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type];
+ unsigned int i;
+
+ if (lchan->ho.active == HANDOVER_NONE)
+ return -1;
+
+ LOGP(DHO, LOGL_ERROR, "%s modifying channel for handover\n",
+ gsm_lchan_name(lchan));
+
+ /* Give up listening to RACH bursts */
+ release_sapis_for_ho(lchan);
+
+ /* Activate the normal SAPIs */
+ for (i = 0; i < s4l->num_sapis; i++) {
+ int sapi = s4l->sapis[i].sapi;
+ int dir = s4l->sapis[i].dir;
+ enqueue_sapi_act_cmd(lchan, sapi, dir);
+ }
+
+ return 0;
}
int bts_model_rsl_chan_rel(struct gsm_lchan *lchan)