Neels Hofmeyr | a2733ae | 2017-11-28 00:29:25 +0100 | [diff] [blame] | 1 | #pragma once |
Holger Hans Peter Freyther | f2553a6 | 2010-06-30 12:58:14 +0800 | [diff] [blame] | 2 | |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 3 | #include <stdint.h> |
| 4 | |
| 5 | #include <osmocom/core/linuxlist.h> |
| 6 | #include <osmocom/core/timer.h> |
| 7 | |
Neels Hofmeyr | a2733ae | 2017-11-28 00:29:25 +0100 | [diff] [blame] | 8 | struct gsm_lchan; |
| 9 | struct gsm_bts; |
Holger Hans Peter Freyther | f2553a6 | 2010-06-30 12:58:14 +0800 | [diff] [blame] | 10 | struct gsm_subscriber_connection; |
| 11 | |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 12 | #define LOGPHOLCHANTOLCHAN(old_lchan, new_lchan, level, fmt, args...) \ |
| 13 | LOGP(DHODEC, level, "(BTS %u trx %u arfcn %u ts %u lchan %u %s)->(BTS %u trx %u arfcn %u ts %u lchan %u %s) (subscr %s) " fmt, \ |
| 14 | old_lchan->ts->trx->bts->nr, \ |
| 15 | old_lchan->ts->trx->nr, \ |
| 16 | old_lchan->ts->trx->arfcn, \ |
| 17 | old_lchan->ts->nr, \ |
| 18 | old_lchan->nr, \ |
| 19 | gsm_pchan_name(old_lchan->ts->pchan), \ |
| 20 | new_lchan->ts->trx->bts->nr, \ |
| 21 | new_lchan->ts->trx->nr, \ |
| 22 | new_lchan->ts->trx->arfcn, \ |
| 23 | new_lchan->ts->nr, \ |
| 24 | new_lchan->nr, \ |
| 25 | gsm_pchan_name(new_lchan->ts->pchan), \ |
| 26 | bsc_subscr_name(old_lchan->conn? old_lchan->conn->bsub : NULL), \ |
| 27 | ## args) |
| 28 | |
| 29 | #define LOGPHO(struct_bsc_handover, level, fmt, args ...) \ |
| 30 | LOGPHOLCHANTOLCHAN(struct_bsc_handover->old_lchan, struct_bsc_handover->new_lchan, level, fmt, ## args) |
| 31 | |
| 32 | enum hodec_id { |
| 33 | HODEC_NONE, |
| 34 | HODEC1 = 1, |
| 35 | HODEC2 = 2, |
| 36 | }; |
| 37 | |
| 38 | struct bsc_handover { |
| 39 | struct llist_head list; |
| 40 | |
| 41 | enum hodec_id from_hodec_id; |
| 42 | |
| 43 | struct gsm_lchan *old_lchan; |
| 44 | struct gsm_lchan *new_lchan; |
| 45 | |
| 46 | struct osmo_timer_list T3103; |
| 47 | |
| 48 | uint8_t ho_ref; |
| 49 | |
| 50 | bool inter_cell; |
| 51 | bool async; |
| 52 | }; |
| 53 | |
| 54 | int bsc_handover_start(enum hodec_id from_hodec_id, struct gsm_lchan *old_lchan, struct gsm_bts *new_bts, |
Neels Hofmeyr | 6dff51d | 2018-02-12 16:56:41 +0100 | [diff] [blame] | 55 | enum gsm_chan_t new_lchan_type); |
Holger Hans Peter Freyther | ebd50a6 | 2010-12-27 13:46:48 +0100 | [diff] [blame] | 56 | void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan); |
Holger Hans Peter Freyther | c121bb3 | 2012-12-26 10:17:42 +0100 | [diff] [blame] | 57 | struct gsm_lchan *bsc_handover_pending(struct gsm_lchan *new_lchan); |
Andreas Eversberg | a918000 | 2013-05-30 11:14:31 +0200 | [diff] [blame] | 58 | |
| 59 | int bsc_ho_count(struct gsm_bts *bts, bool inter_cell); |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 60 | |
| 61 | /* Handover decision algorithms' actions to take on incoming handover-relevant events. |
| 62 | * |
| 63 | * All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, |
| 64 | * so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up |
| 65 | * handover operation state upon receiving some of these signals. To allow a handover decision algorithm |
| 66 | * to take advantage of e.g. the struct bsc_handover before it is discarded, the handover decision event |
| 67 | * handler needs to be invoked before handover_logic.c discards the state. For example, if the handover |
| 68 | * decision wants to place a penalty timer upon a handover failure, it still needs to know which target |
| 69 | * cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it |
| 70 | * needs to clean up the lchan's handover state. |
| 71 | * |
| 72 | * The most explicit and safest way to ensure the correct order of event handling is to invoke the |
| 73 | * handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct |
| 74 | * provides the callback functions for this purpose. |
| 75 | * |
| 76 | * For consistency, also handle signals in this way that aren't actually in danger of interference from |
| 77 | * handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover |
| 78 | * decision algorithms should not register any signal handler at all. |
| 79 | */ |
| 80 | struct handover_decision_callbacks { |
| 81 | struct llist_head entry; |
| 82 | |
| 83 | int hodec_id; |
| 84 | |
| 85 | void (*on_measurement_report)(struct gsm_meas_rep *mr); |
| 86 | void (*on_ho_chan_activ_nack)(struct bsc_handover *ho); |
| 87 | void (*on_ho_failure)(struct bsc_handover *ho); |
| 88 | }; |
| 89 | |
| 90 | void handover_decision_callbacks_register(struct handover_decision_callbacks *hdc); |
| 91 | struct handover_decision_callbacks *handover_decision_callbacks_get(int hodec_id); |