blob: aa117cc24a08f3d3d6921383561fb9ef471dbb7b [file] [log] [blame]
Neels Hofmeyra2733ae2017-11-28 00:29:25 +01001#pragma once
Holger Hans Peter Freytherf2553a62010-06-30 12:58:14 +08002
Neels Hofmeyr45e46d22018-02-15 14:10:12 +01003#include <stdint.h>
4
5#include <osmocom/core/linuxlist.h>
6#include <osmocom/core/timer.h>
Harald Welte3561bd42018-01-28 03:04:16 +01007#include <osmocom/gsm/gsm_utils.h>
Neels Hofmeyr45e46d22018-02-15 14:10:12 +01008
Neels Hofmeyr19bed232018-03-22 04:54:57 +01009#include <osmocom/bsc/neighbor_ident.h>
10
Neels Hofmeyra2733ae2017-11-28 00:29:25 +010011struct gsm_lchan;
12struct gsm_bts;
Holger Hans Peter Freytherf2553a62010-06-30 12:58:14 +080013struct gsm_subscriber_connection;
Harald Welte3561bd42018-01-28 03:04:16 +010014struct gsm_meas_rep mr;
Holger Hans Peter Freytherf2553a62010-06-30 12:58:14 +080015
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010016#define LOGPHOLCHANTOLCHAN(old_lchan, new_lchan, level, fmt, args...) \
Neels Hofmeyr31716f92018-07-19 16:14:09 +020017 LOGP(DHODEC, level, "(BTS %u trx %u arfcn %u ts %u lchan %u %s %s)->(BTS %u trx %u arfcn %u ts %u lchan %u %s) (subscr %s) " fmt, \
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010018 old_lchan->ts->trx->bts->nr, \
19 old_lchan->ts->trx->nr, \
20 old_lchan->ts->trx->arfcn, \
21 old_lchan->ts->nr, \
22 old_lchan->nr, \
Neels Hofmeyr31716f92018-07-19 16:14:09 +020023 gsm_lchant_name(old_lchan->type), \
24 gsm48_chan_mode_name(old_lchan->tch_mode), \
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010025 new_lchan->ts->trx->bts->nr, \
26 new_lchan->ts->trx->nr, \
27 new_lchan->ts->trx->arfcn, \
28 new_lchan->ts->nr, \
29 new_lchan->nr, \
30 gsm_pchan_name(new_lchan->ts->pchan), \
31 bsc_subscr_name(old_lchan->conn? old_lchan->conn->bsub : NULL), \
32 ## args)
33
34#define LOGPHO(struct_bsc_handover, level, fmt, args ...) \
35 LOGPHOLCHANTOLCHAN(struct_bsc_handover->old_lchan, struct_bsc_handover->new_lchan, level, fmt, ## args)
36
37enum hodec_id {
38 HODEC_NONE,
39 HODEC1 = 1,
40 HODEC2 = 2,
41};
42
43struct bsc_handover {
44 struct llist_head list;
45
Harald Welte3561bd42018-01-28 03:04:16 +010046 /* Initial details of what is requested */
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010047 struct gsm_lchan *old_lchan;
Harald Welte3561bd42018-01-28 03:04:16 +010048 struct gsm_bts *new_bts;
49 enum gsm_chan_t new_lchan_type;
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010050 bool async;
Harald Welte3561bd42018-01-28 03:04:16 +010051
52 /* Derived and resulting state */
53 bool inter_cell;
54 uint8_t ho_ref;
55 enum hodec_id from_hodec_id;
56 struct gsm_lchan *new_lchan;
57 struct osmo_timer_list T3103;
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010058};
59
60int bsc_handover_start(enum hodec_id from_hodec_id, struct gsm_lchan *old_lchan, struct gsm_bts *new_bts,
Neels Hofmeyr6dff51d2018-02-12 16:56:41 +010061 enum gsm_chan_t new_lchan_type);
Harald Welte3561bd42018-01-28 03:04:16 +010062int bsc_handover_start_gscon(struct gsm_subscriber_connection *conn);
Holger Hans Peter Freytherebd50a62010-12-27 13:46:48 +010063void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan);
Holger Hans Peter Freytherc121bb32012-12-26 10:17:42 +010064struct gsm_lchan *bsc_handover_pending(struct gsm_lchan *new_lchan);
Andreas Eversberga9180002013-05-30 11:14:31 +020065
66int bsc_ho_count(struct gsm_bts *bts, bool inter_cell);
Neels Hofmeyr45e46d22018-02-15 14:10:12 +010067
68/* Handover decision algorithms' actions to take on incoming handover-relevant events.
69 *
70 * All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals,
71 * so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up
72 * handover operation state upon receiving some of these signals. To allow a handover decision algorithm
73 * to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event
74 * handler needs to be invoked before handover_logic.c discards the state. For example, if the handover
75 * decision wants to place a penalty timer upon a handover failure, it still needs to know which target
76 * cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it
77 * needs to clean up the lchan's handover state.
78 *
79 * The most explicit and safest way to ensure the correct order of event handling is to invoke the
80 * handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct
81 * provides the callback functions for this purpose.
82 *
83 * For consistency, also handle signals in this way that aren't actually in danger of interference from
84 * handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover
85 * decision algorithms should not register any signal handler at all.
86 */
87struct handover_decision_callbacks {
88 struct llist_head entry;
89
90 int hodec_id;
91
92 void (*on_measurement_report)(struct gsm_meas_rep *mr);
93 void (*on_ho_chan_activ_nack)(struct bsc_handover *ho);
94 void (*on_ho_failure)(struct bsc_handover *ho);
95};
96
97void handover_decision_callbacks_register(struct handover_decision_callbacks *hdc);
98struct handover_decision_callbacks *handover_decision_callbacks_get(int hodec_id);
Neels Hofmeyr19bed232018-03-22 04:54:57 +010099
100struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
101 const struct neighbor_ident_key *search_for);
102struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);