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> |
Harald Welte | 3561bd4 | 2018-01-28 03:04:16 +0100 | [diff] [blame] | 7 | #include <osmocom/gsm/gsm_utils.h> |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 8 | #include <osmocom/gsm/gsm0808.h> |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 9 | |
Neels Hofmeyr | 19bed23 | 2018-03-22 04:54:57 +0100 | [diff] [blame] | 10 | #include <osmocom/bsc/neighbor_ident.h> |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 11 | #include <osmocom/bsc/gsm_data.h> |
Neels Hofmeyr | 19bed23 | 2018-03-22 04:54:57 +0100 | [diff] [blame] | 12 | |
Neels Hofmeyr | 91a202d | 2019-07-13 01:12:53 +0200 | [diff] [blame] | 13 | #define LOG_HO(conn, level, fmt, args...) do { \ |
| 14 | if (conn->ho.fi) \ |
| 15 | LOGPFSML(conn->ho.fi, level, "%s: " fmt, \ |
| 16 | handover_status(conn), ## args); \ |
| 17 | else \ |
| 18 | LOGP(DHODEC, level, "%s: " fmt, \ |
| 19 | handover_status(conn), ## args); \ |
| 20 | } while(0) |
| 21 | |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 22 | struct gsm_network; |
Neels Hofmeyr | a2733ae | 2017-11-28 00:29:25 +0100 | [diff] [blame] | 23 | struct gsm_lchan; |
| 24 | struct gsm_bts; |
Holger Hans Peter Freyther | f2553a6 | 2010-06-30 12:58:14 +0800 | [diff] [blame] | 25 | struct gsm_subscriber_connection; |
Harald Welte | 7463285 | 2020-04-20 19:58:53 +0200 | [diff] [blame] | 26 | struct gsm_meas_rep; |
Holger Hans Peter Freyther | f2553a6 | 2010-06-30 12:58:14 +0800 | [diff] [blame] | 27 | |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 28 | enum handover_result { |
| 29 | HO_RESULT_OK, |
| 30 | HO_RESULT_FAIL_NO_CHANNEL, |
| 31 | HO_RESULT_FAIL_RR_HO_FAIL, |
| 32 | HO_RESULT_FAIL_TIMEOUT, |
| 33 | HO_RESULT_CONN_RELEASE, |
| 34 | HO_RESULT_ERROR, |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 35 | }; |
| 36 | |
Neels Hofmeyr | 91a202d | 2019-07-13 01:12:53 +0200 | [diff] [blame] | 37 | const char *handover_status(struct gsm_subscriber_connection *conn); |
| 38 | |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 39 | extern const struct value_string handover_result_names[]; |
| 40 | inline static const char *handover_result_name(enum handover_result val) |
| 41 | { return get_value_string(handover_result_names, val); } |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 42 | |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 43 | int bts_handover_count(struct gsm_bts *bts, int ho_scopes); |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 44 | |
| 45 | /* Handover decision algorithms' actions to take on incoming handover-relevant events. |
| 46 | * |
| 47 | * All events that are interesting for handover decision are actually communicated by S_LCHAN_* signals, |
| 48 | * so theoretically, each handover algorithm could evaluate those. However, handover_logic.c cleans up |
| 49 | * handover operation state upon receiving some of these signals. To allow a handover decision algorithm |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 50 | * to take advantage of e.g. the struct handover before it is discarded, the handover decision event |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 51 | * handler needs to be invoked before handover_logic.c discards the state. For example, if the handover |
| 52 | * decision wants to place a penalty timer upon a handover failure, it still needs to know which target |
| 53 | * cell the handover failed for; handover_logic.c erases that knowledge on handover failure, since it |
| 54 | * needs to clean up the lchan's handover state. |
| 55 | * |
| 56 | * The most explicit and safest way to ensure the correct order of event handling is to invoke the |
| 57 | * handover decision algorithm's actions from handover_logic.c itself, before cleaning up. This struct |
| 58 | * provides the callback functions for this purpose. |
| 59 | * |
| 60 | * For consistency, also handle signals in this way that aren't actually in danger of interference from |
| 61 | * handover_logic.c (which also saves repeated lookup of handover state for lchans). Thus, handover |
| 62 | * decision algorithms should not register any signal handler at all. |
| 63 | */ |
| 64 | struct handover_decision_callbacks { |
| 65 | struct llist_head entry; |
| 66 | |
| 67 | int hodec_id; |
| 68 | |
| 69 | void (*on_measurement_report)(struct gsm_meas_rep *mr); |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 70 | void (*on_handover_end)(struct gsm_subscriber_connection *conn, enum handover_result result); |
Neels Hofmeyr | 45e46d2 | 2018-02-15 14:10:12 +0100 | [diff] [blame] | 71 | }; |
| 72 | |
| 73 | void handover_decision_callbacks_register(struct handover_decision_callbacks *hdc); |
| 74 | struct handover_decision_callbacks *handover_decision_callbacks_get(int hodec_id); |
Neels Hofmeyr | 19bed23 | 2018-03-22 04:54:57 +0100 | [diff] [blame] | 75 | |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 76 | int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell_id_list2 *target_cells); |
| 77 | int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, |
| 78 | struct msgb *rr_ho_command); |
| 79 | int bsc_tx_bssmap_ho_detect(struct gsm_subscriber_connection *conn); |
| 80 | enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn, |
| 81 | struct gsm_lchan *lchan); |
| 82 | void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn); |
| 83 | |
Neels Hofmeyr | 91a202d | 2019-07-13 01:12:53 +0200 | [diff] [blame] | 84 | int find_handover_target_cell(struct gsm_bts **local_target_cell_p, |
| 85 | const struct gsm0808_cell_id_list2 **remote_target_cell_p, |
| 86 | struct gsm_subscriber_connection *conn, const struct neighbor_ident_key *search_for, |
| 87 | bool log_errors); |
| 88 | |
Neels Hofmeyr | 19bed23 | 2018-03-22 04:54:57 +0100 | [diff] [blame] | 89 | struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts); |
Neels Hofmeyr | 31f525e | 2018-05-14 18:14:15 +0200 | [diff] [blame] | 90 | |
| 91 | void handover_parse_inter_bsc_mt(struct gsm_subscriber_connection *conn, |
| 92 | struct msgb *ho_request_msg); |
| 93 | |
| 94 | void handover_mt_allocate_lchan(struct handover *ho); |
| 95 | int handover_mt_send_rr_ho_command(struct handover *ho); |