aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2009-12-17 00:31:10 +0100
committerHarald Welte <laforge@netfilter.org>2009-12-17 00:31:10 +0100
commit8d77b9540a907fb36afbb324df549c9261e1ca02 (patch)
treed616821b44f212c8f7159cfd206bbc44ca41666b /openbsc
parent7a7a0d54289114e6a49087a555b7a4f1e6cb3016 (diff)
[handover] first functional handover implementation
With this commit, we can successfully hand over a channel from one cell to another cell. We implement asynchronous intra-BSC (but inter-BTS) handover. Changes: * introduce new DHO log category * extend rsl_chan_activate_lchan() with argument for HO reference * introduce actual minimal handover decision making in handover_decision.c * various fixes to bsc_handover_start() in handover_logic.c
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/abis_rsl.h2
-rw-r--r--openbsc/include/openbsc/debug.h2
-rw-r--r--openbsc/include/openbsc/handover.h8
-rw-r--r--openbsc/src/Makefile.am3
-rw-r--r--openbsc/src/abis_rsl.c15
-rw-r--r--openbsc/src/bsc_hack.c1
-rw-r--r--openbsc/src/bsc_init.c1
-rw-r--r--openbsc/src/debug.c3
-rw-r--r--openbsc/src/handover_decision.c111
-rw-r--r--openbsc/src/handover_logic.c27
10 files changed, 164 insertions, 9 deletions
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index b76d0facc..6d0ab6182 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -497,7 +497,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
u_int8_t bs_power, u_int8_t ms_power,
u_int8_t ta);
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
- u_int8_t ta);
+ u_int8_t ta, u_int8_t ho_ref);
int rsl_chan_mode_modify_req(struct gsm_lchan *ts);
int rsl_encryption_cmd(struct msgb *msg);
int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 447c3584f..c1098a53c 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -25,6 +25,8 @@
#define DMGCP 0x40000
+#define DHO 0x80000
+
#ifdef DEBUG
#define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args)
#define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args)
diff --git a/openbsc/include/openbsc/handover.h b/openbsc/include/openbsc/handover.h
new file mode 100644
index 000000000..8ab1b0642
--- /dev/null
+++ b/openbsc/include/openbsc/handover.h
@@ -0,0 +1,8 @@
+#ifndef _HANDOVER_H
+#define _HANDOVER_H
+/* Hand over the specified logical channel to the specified new BTS.
+ * This is the main entry point for the actual handover algorithm,
+ * after it has decided it wants to initiate HO to a specific BTS */
+int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts);
+
+#endif /* _HANDOVER_H */
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index f22582122..5692ac4e4 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -11,7 +11,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
- talloc_ctx.c system_information.c bitvec.c rest_octets.c
+ talloc_ctx.c system_information.c bitvec.c rest_octets.c \
+ handover_decision.c
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 1fbea837d..d42daf5f2 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -576,7 +576,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
#endif
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
- u_int8_t ta)
+ u_int8_t ta, u_int8_t ho_ref)
{
struct abis_rsl_dchan_hdr *dh;
struct msgb *msg;
@@ -603,9 +603,9 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
dh->chan_nr = chan_nr;
msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
- /* For compatibility with Phase 1 */
msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
(u_int8_t *) &cm);
+ /* For compatibility with Phase 1 */
msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
(u_int8_t *) &ci);
@@ -616,6 +616,15 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
}
+ switch (act_type) {
+ case RSL_ACT_INTER_ASYNC:
+ case RSL_ACT_INTER_SYNC:
+ msgb_tv_put(msg, RSL_IE_HANDO_REF, ho_ref);
+ break;
+ default:
+ break;
+ }
+
msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
@@ -1258,7 +1267,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lchan->bs_power = 0; /* 0dB reduction, output power = Pn */
lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
lchan->tch_mode = GSM48_CMODE_SIGN;
- rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
+ rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0);
/* create IMMEDIATE ASSIGN 04.08 messge */
memset(&ia, 0, sizeof(ia));
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 1dd5e1020..b0f8d6c3f 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -162,6 +162,7 @@ int main(int argc, char **argv)
talloc_ctx_init();
on_dso_load_token();
on_dso_load_rrlp();
+ on_dso_load_ho_dec();
/* parse options */
handle_options(argc, argv);
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index aed0dad42..ce3d0b4f8 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -679,6 +679,7 @@ static int set_system_infos(struct gsm_bts_trx *trx)
rc = gsm_generate_si(si_tmp, trx->bts, i);
if (rc < 0)
goto err_out;
+ DEBUGP(DRR, "SI%u: %s\n", i, hexdump(si_tmp, rc));
rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
}
}
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 5dc2e0ff7..9c6cb4963 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -28,7 +28,7 @@
#include <openbsc/debug.h>
-unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB|DMEAS);
+unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB);
struct debug_info {
const char *name;
@@ -60,6 +60,7 @@ static const struct debug_info debug_info[] = {
DEBUG_CATEGORY(DSCCP, "DSCCP", "", "")
DEBUG_CATEGORY(DMSC, "DMSC", "", "")
DEBUG_CATEGORY(DMGCP, "DMGCP", "", "")
+ DEBUG_CATEGORY(DHO, "DHO", "", "")
};
static int use_color = 1;
diff --git a/openbsc/src/handover_decision.c b/openbsc/src/handover_decision.c
new file mode 100644
index 000000000..06eb86507
--- /dev/null
+++ b/openbsc/src/handover_decision.c
@@ -0,0 +1,111 @@
+/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This
+ * only implements the handover algorithm/decision, but not execution
+ * of it */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * 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 <stdlib.h>
+#include <errno.h>
+
+#include <openbsc/msgb.h>
+#include <openbsc/debug.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/meas_rep.h>
+#include <openbsc/signal.h>
+#include <openbsc/talloc.h>
+#include <openbsc/handover.h>
+
+static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
+ u_int16_t arfcn, u_int8_t bsic)
+{
+ struct gsm_bts *new_bts;
+
+ /* resolve the gsm_bts structure for the best neighbor */
+ new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic);
+ if (!new_bts) {
+ DEBUGP(DHO, "unable to determine neighbor BTS for ARFCN %u BSIC %u ?!?\n", arfcn, bsic);
+ return -EINVAL;
+ }
+
+ /* and actually try to handover to that cell */
+ return bsc_handover_start(lchan, new_bts);
+}
+
+#define RXLEV_HYST 3
+
+/* process an already parsed measurement report */
+static int process_meas_rep(struct gsm_meas_rep *mr)
+{
+ struct gsm_meas_rep_cell *mr_cell = NULL;
+ unsigned int best_better_db;
+ int i;
+
+ DEBUGP(DHO, "process meas res: ");
+
+ /* FIXME: implement actual averaging over multiple measurement
+ * reports */
+
+ /* find the best cell in this report that is at least RXLEV_HYST
+ * better than the current serving cell */
+ for (i = 0; i < mr->num_cell; i++) {
+ unsigned int better;
+ if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST)
+ continue;
+
+ better = mr->cell[i].rxlev - mr->dl.full.rx_lev;
+ if (better > best_better_db) {
+ mr_cell = &mr->cell[i];
+ best_better_db = better;
+ }
+ }
+
+ if (mr_cell) {
+ DEBUGPC(DHO, "Cell on ARFCN %u is better, starting handover\n", mr_cell->arfcn);
+ return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn,
+ mr_cell->bsic);
+ }
+
+ DEBUGPC(DHO, "No better cell\n");
+ return 0;
+}
+
+static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct gsm_meas_rep *mr;
+
+ if (subsys != SS_LCHAN)
+ return 0;
+
+ switch (signal) {
+ case S_LCHAN_MEAS_REP:
+ mr = signal_data;
+ process_meas_rep(mr);
+ break;
+ }
+
+ return 0;
+}
+
+void on_dso_load_ho_dec(void)
+{
+ register_signal_handler(SS_LCHAN, ho_dec_sig_cb, NULL);
+}
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index d4a888487..99b3c0139 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -85,23 +85,40 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
{
struct gsm_lchan *new_lchan;
struct bsc_handover *ho;
+ static u_int8_t ho_ref;
int rc;
+ DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u): ",
+ old_lchan->ts->trx->bts->nr, bts->nr);
+
new_lchan = lchan_alloc(bts, old_lchan->type);
- if (!new_lchan)
+ if (!new_lchan) {
+ DEBUGPC(DHO, "No free channel\n");
return -ENOSPC;
+ }
ho = talloc_zero(NULL, struct bsc_handover);
if (!ho) {
+ DEBUGPC(DHO, "Out of Memory\n");
lchan_free(new_lchan);
return -ENOMEM;
}
ho->old_lchan = old_lchan;
ho->new_lchan = new_lchan;
+ ho->ho_ref = ho_ref++;
+
+ /* copy some parameters from old lchan */
+ memcpy(&new_lchan->encr, &old_lchan->encr, sizeof(new_lchan->encr));
+ new_lchan->ms_power = old_lchan->ms_power;
+ new_lchan->bs_power = old_lchan->bs_power;
+ new_lchan->rsl_cmode = old_lchan->rsl_cmode;
+ new_lchan->tch_mode = old_lchan->tch_mode;
/* FIXME: do we have a better idea of the timing advance? */
- rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0);
+ rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
+ ho->ho_ref);
if (rc < 0) {
+ DEBUGPC(DHO, "could not activate channel\n");
talloc_free(ho);
lchan_free(new_lchan);
return rc;
@@ -118,6 +135,8 @@ static void ho_T3103_cb(void *_ho)
{
struct bsc_handover *ho = _ho;
+ DEBUGP(DHO, "HO T3103 expired\n");
+
lchan_free(ho->new_lchan);
llist_del(&ho->list);
talloc_free(ho);
@@ -129,6 +148,8 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)
struct bsc_handover *ho;
int rc;
+ DEBUGP(DHO, "handover activate ack, send HO Command\n");
+
ho = bsc_ho_by_new_lchan(new_lchan);
if (!ho)
return -ENODEV;
@@ -136,7 +157,7 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)
/* we can now send the 04.08 HANDOVER COMMAND to the MS
* using the old lchan */
- rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0);
+ rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref);
/* start T3103. We can continue either with T3103 expiration,
* 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */