aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/handover_logic.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-03-03 23:29:05 +0100
committerHarald Welte <laforge@gnumonks.org>2011-03-03 23:29:05 +0100
commit31c00f7d6fa63937f2c973157d196a427f6eef95 (patch)
tree6b7c81d92b6a8b83d0588b2b59d47fd0cca7a052 /openbsc/src/handover_logic.c
parent9349d7ff7c5866110a1f2421ccc68a487e4030be (diff)
re-structure the OpenBSC directory layout
The new structure divides the code into a number of libraries for the BSC core functionality, MSC core functionality, Abis transport, TRAU and other bits. This doesn't introduce any functional code change but simply moves around files and alters Makefile.am accordingly. Next step would be to disentangle a lot of the inter-library dependencies and make the individual bits of code more independent.
Diffstat (limited to 'openbsc/src/handover_logic.c')
-rw-r--r--openbsc/src/handover_logic.c393
1 files changed, 0 insertions, 393 deletions
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
deleted file mode 100644
index c2e3f8c72..000000000
--- a/openbsc/src/handover_logic.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/* Handover Logic for Inter-BTS (Intra-BSC) Handover. This does not
- * actually implement the handover algorithm/decision, but executes a
- * handover decision */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <netinet/in.h>
-
-#include <osmocore/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <osmocore/gsm_utils.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/signal.h>
-#include <osmocore/talloc.h>
-#include <openbsc/transaction.h>
-#include <openbsc/rtp_proxy.h>
-
-struct bsc_handover {
- struct llist_head list;
-
- struct gsm_lchan *old_lchan;
- struct gsm_lchan *new_lchan;
-
- struct timer_list T3103;
-
- u_int8_t ho_ref;
-};
-
-static LLIST_HEAD(bsc_handovers);
-
-static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- llist_for_each_entry(ho, &bsc_handovers, list) {
- if (ho->new_lchan == new_lchan)
- return ho;
- }
-
- return NULL;
-}
-
-static struct bsc_handover *bsc_ho_by_old_lchan(struct gsm_lchan *old_lchan)
-{
- struct bsc_handover *ho;
-
- llist_for_each_entry(ho, &bsc_handovers, list) {
- if (ho->old_lchan == old_lchan)
- return ho;
- }
-
- return NULL;
-}
-
-/* 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)
-{
- struct gsm_lchan *new_lchan;
- struct bsc_handover *ho;
- static u_int8_t ho_ref;
- int rc;
-
- /* don't attempt multiple handovers for the same lchan at
- * the same time */
- if (bsc_ho_by_old_lchan(old_lchan))
- return -EBUSY;
-
- DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
- old_lchan->ts->trx->bts->nr, bts->nr);
-
- counter_inc(bts->network->stats.handover.attempted);
-
- if (!old_lchan->conn) {
- LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n");
- return -ENOSPC;
- }
-
- new_lchan = lchan_alloc(bts, old_lchan->type, 0);
- if (!new_lchan) {
- LOGP(DHO, LOGL_NOTICE, "No free channel\n");
- counter_inc(bts->network->stats.handover.no_channel);
- return -ENOSPC;
- }
-
- ho = talloc_zero(tall_bsc_ctx, struct bsc_handover);
- if (!ho) {
- LOGP(DHO, LOGL_FATAL, "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;
-
- new_lchan->conn = old_lchan->conn;
- new_lchan->conn->ho_lchan = new_lchan;
-
- /* FIXME: do we have a better idea of the timing advance? */
- rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
- ho->ho_ref);
- if (rc < 0) {
- LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn = NULL;
- talloc_free(ho);
- lchan_free(new_lchan);
- return rc;
- }
-
- rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
- llist_add(&ho->list, &bsc_handovers);
- /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
-
- return 0;
-}
-
-void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(conn->ho_lchan);
-
-
- if (!ho && conn->ho_lchan)
- LOGP(DHO, LOGL_ERROR, "BUG: We lost some state.\n");
-
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return;
- }
-
- conn->ho_lchan->conn = NULL;
- conn->ho_lchan = NULL;
-
- if (free_lchan)
- lchan_release(ho->new_lchan, 0, 1);
-
- bsc_del_timer(&ho->T3103);
- llist_del(&ho->list);
- talloc_free(ho);
-}
-
-/* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */
-static void ho_T3103_cb(void *_ho)
-{
- struct bsc_handover *ho = _ho;
- struct gsm_network *net = ho->new_lchan->ts->trx->bts->network;
-
- DEBUGP(DHO, "HO T3103 expired\n");
- counter_inc(net->stats.handover.timeout);
-
- ho->new_lchan->conn->ho_lchan = NULL;
- ho->new_lchan->conn = NULL;
- lchan_release(ho->new_lchan, 0, 1);
- llist_del(&ho->list);
- talloc_free(ho);
-}
-
-/* RSL has acknowledged activation of the new lchan */
-static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
- int rc;
-
- /* we need to check if this channel activation is related to
- * a handover at all (and if, which particular handover) */
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho)
- return -ENODEV;
-
- DEBUGP(DHO, "handover activate ack, send HO Command\n");
-
- /* 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, ho->ho_ref);
-
- /* start T3103. We can continue either with T3103 expiration,
- * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */
- ho->T3103.cb = ho_T3103_cb;
- ho->T3103.data = ho;
- bsc_schedule_timer(&ho->T3103, 10, 0);
-
- /* create a RTP connection */
- if (is_ipaccess_bts(new_lchan->ts->trx->bts))
- rsl_ipacc_crcx(new_lchan);
-
- return 0;
-}
-
-/* RSL has not acknowledged activation of the new lchan */
-static int ho_chan_activ_nack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn = NULL;
- llist_del(&ho->list);
- talloc_free(ho);
-
- /* FIXME: maybe we should try to allocate a new LCHAN here? */
-
- return 0;
-}
-
-/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */
-static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
-{
- struct gsm_network *net;
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- net = new_lchan->ts->trx->bts->network;
- LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
- "%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
- ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
- ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
-
- counter_inc(net->stats.handover.completed);
-
- bsc_del_timer(&ho->T3103);
-
- /* Replace the ho lchan with the primary one */
- if (ho->old_lchan != new_lchan->conn->lchan)
- LOGP(DHO, LOGL_ERROR, "Primary lchan changed during handover.\n");
-
- if (new_lchan != new_lchan->conn->ho_lchan)
- LOGP(DHO, LOGL_ERROR, "Handover channel changed during this handover.\n");
-
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn->lchan = new_lchan;
- ho->old_lchan->conn = NULL;
-
- rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
- lchan_release(ho->old_lchan, 0, 1);
-
- /* do something to re-route the actual speech frames ! */
-
- llist_del(&ho->list);
- talloc_free(ho);
-
- return 0;
-}
-
-/* GSM 04.08 HANDOVER FAIL has been received */
-static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
-{
- struct gsm_network *net = old_lchan->ts->trx->bts->network;
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_old_lchan(old_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- counter_inc(net->stats.handover.failed);
-
- bsc_del_timer(&ho->T3103);
- llist_del(&ho->list);
-
- /* release the channel and forget about it */
- ho->new_lchan->conn->ho_lchan = NULL;
- ho->new_lchan->conn = NULL;
- lchan_release(ho->new_lchan, 0, 1);
-
- talloc_free(ho);
-
- return 0;
-}
-
-/* GSM 08.58 HANDOVER DETECT has been received */
-static int ho_rsl_detect(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- /* FIXME: do we actually want to do something here ? */
-
- return 0;
-}
-
-static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
- struct ho_signal_data sig_ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- /* it is perfectly normal, we have CRCX even in non-HO cases */
- return 0;
- }
-
- sig_ho.old_lchan = ho->old_lchan;
- sig_ho.new_lchan = new_lchan;
- dispatch_signal(SS_HO, S_HANDOVER_ACK, &sig_ho);
- return 0;
-}
-
-static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct lchan_signal_data *lchan_data;
- struct gsm_lchan *lchan;
-
- lchan_data = signal_data;
- switch (subsys) {
- case SS_LCHAN:
- lchan = lchan_data->lchan;
- switch (signal) {
- case S_LCHAN_ACTIVATE_ACK:
- return ho_chan_activ_ack(lchan);
- case S_LCHAN_ACTIVATE_NACK:
- return ho_chan_activ_nack(lchan);
- case S_LCHAN_HANDOVER_DETECT:
- return ho_rsl_detect(lchan);
- case S_LCHAN_HANDOVER_COMPL:
- return ho_gsm48_ho_compl(lchan);
- case S_LCHAN_HANDOVER_FAIL:
- return ho_gsm48_ho_fail(lchan);
- }
- break;
- case SS_ABISIP:
- lchan = signal_data;
- switch (signal) {
- case S_ABISIP_CRCX_ACK:
- return ho_ipac_crcx_ack(lchan);
- break;
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_ho_logic(void)
-{
- register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL);
- register_signal_handler(SS_ABISIP, ho_logic_sig_cb, NULL);
-}