blob: 2aa48b713c26b9de94e0009de4da37e22a8d0443 [file] [log] [blame]
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001/*
2 * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <errno.h>
23
24#include <assert.h>
25
26#include <osmocom/core/application.h>
27#include <osmocom/core/select.h>
28#include <osmocom/core/talloc.h>
29
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020030#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
Pau Espin Pedrole2490452018-03-17 01:16:54 +010031
Neels Hofmeyr909e9722017-12-07 03:54:01 +010032#include <osmocom/bsc/abis_rsl.h>
33#include <osmocom/bsc/debug.h>
34#include <osmocom/bsc/bsc_subscriber.h>
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020035#include <osmocom/bsc/lchan_select.h>
36#include <osmocom/bsc/lchan_fsm.h>
Neels Hofmeyr909e9722017-12-07 03:54:01 +010037#include <osmocom/bsc/handover_decision.h>
38#include <osmocom/bsc/system_information.h>
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020039#include <osmocom/bsc/handover.h>
Neels Hofmeyr909e9722017-12-07 03:54:01 +010040#include <osmocom/bsc/handover_cfg.h>
41#include <osmocom/bsc/handover_decision_2.h>
Neels Hofmeyr909e9722017-12-07 03:54:01 +010042#include <osmocom/bsc/bss.h>
Neels Hofmeyr81a49632018-07-24 18:10:05 +020043#include <osmocom/bsc/gsm_08_08.h>
Neels Hofmeyr909e9722017-12-07 03:54:01 +010044#include <osmocom/bsc/osmo_bsc.h>
Harald Welte3561bd42018-01-28 03:04:16 +010045#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020046#include <osmocom/bsc/timeslot_fsm.h>
47#include <osmocom/bsc/lchan_fsm.h>
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020048#include <osmocom/bsc/handover_fsm.h>
49#include <osmocom/bsc/bsc_msc_data.h>
Pau Espin Pedrol388ed582020-07-15 20:53:16 +020050#include <osmocom/bsc/bts.h>
Neels Hofmeyr86ce1052020-09-18 02:49:32 +020051#include <osmocom/bsc/paging.h>
Neels Hofmeyr909e9722017-12-07 03:54:01 +010052
Neels Hofmeyre3416182018-03-05 05:31:14 +010053void *ctx;
54
Neels Hofmeyr909e9722017-12-07 03:54:01 +010055struct gsm_network *bsc_gsmnet;
56
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020057/* override, requires '-Wl,--wrap=osmo_mgcpc_ep_ci_request'.
Harald Welte3561bd42018-01-28 03:04:16 +010058 * Catch modification of an MGCP connection. */
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020059void __real_osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020060 enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
61 struct osmo_fsm_inst *notify,
62 uint32_t event_success, uint32_t event_failure,
63 void *notify_data);
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020064void __wrap_osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020065 enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
66 struct osmo_fsm_inst *notify,
67 uint32_t event_success, uint32_t event_failure,
68 void *notify_data)
Harald Welte3561bd42018-01-28 03:04:16 +010069{
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020070 struct mgcp_conn_peer fake_data = {};
71 /* All MGCP shall be successful */
72 if (!notify)
73 return;
74 osmo_fsm_inst_dispatch(notify, event_success, &fake_data);
Harald Welte3561bd42018-01-28 03:04:16 +010075}
76
Neels Hofmeyr909e9722017-12-07 03:54:01 +010077/* measurement report */
78
79uint8_t meas_rep_ba = 0, meas_rep_valid = 1, meas_valid = 1, meas_multi_rep = 0;
80uint8_t meas_dl_rxlev = 0, meas_dl_rxqual = 0;
81uint8_t meas_ul_rxlev = 0, meas_ul_rxqual = 0;
82uint8_t meas_tx_power_ms = 0, meas_tx_power_bs = 0, meas_ta_ms = 0;
83uint8_t meas_dtx_ms = 0, meas_dtx_bs = 0, meas_nr = 0;
84uint8_t meas_num_nc = 0, meas_rxlev_nc[6], meas_bsic_nc[6], meas_bcch_f_nc[6];
85
86static void gen_meas_rep(struct gsm_lchan *lchan)
87{
88 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
89 struct abis_rsl_dchan_hdr *dh;
90 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
91 uint8_t ulm[3], l1i[2], *buf;
92 struct gsm48_hdr *gh;
93 struct gsm48_meas_res *mr;
94
95 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
96 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
97 dh->c.msg_type = RSL_MT_MEAS_RES;
98 dh->ie_chan = RSL_IE_CHAN_NR;
99 dh->chan_nr = chan_nr;
100
101 msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, meas_nr++);
102
103 ulm[0] = meas_ul_rxlev | (meas_dtx_bs << 7);
104 ulm[1] = meas_ul_rxlev;
105 ulm[2] = (meas_ul_rxqual << 3) | meas_ul_rxqual;
106 msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, sizeof(ulm), ulm);
107
108 msgb_tv_put(msg, RSL_IE_BS_POWER, meas_tx_power_bs);
109
110 l1i[0] = 0;
111 l1i[1] = meas_ta_ms;
112 msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, sizeof(l1i), l1i);
113
114 buf = msgb_put(msg, 3);
115 buf[0] = RSL_IE_L3_INFO;
116 buf[1] = (sizeof(*gh) + sizeof(*mr)) >> 8;
117 buf[2] = (sizeof(*gh) + sizeof(*mr)) & 0xff;
118
119 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
120 mr = (struct gsm48_meas_res *) msgb_put(msg, sizeof(*mr));
121
122 gh->proto_discr = GSM48_PDISC_RR;
123 gh->msg_type = GSM48_MT_RR_MEAS_REP;
124
125 /* measurement results */
126 mr->rxlev_full = meas_dl_rxlev;
127 mr->rxlev_sub = meas_dl_rxlev;
128 mr->rxqual_full = meas_dl_rxqual;
129 mr->rxqual_sub = meas_dl_rxqual;
130 mr->dtx_used = meas_dtx_ms;
131 mr->ba_used = meas_rep_ba;
132 mr->meas_valid = !meas_valid; /* 0 = valid */
133 if (meas_rep_valid) {
134 mr->no_nc_n_hi = meas_num_nc >> 2;
135 mr->no_nc_n_lo = meas_num_nc & 3;
136 } else {
137 /* no results for serving cells */
138 mr->no_nc_n_hi = 1;
139 mr->no_nc_n_lo = 3;
140 }
141 mr->rxlev_nc1 = meas_rxlev_nc[0];
142 mr->rxlev_nc2_hi = meas_rxlev_nc[1] >> 1;
143 mr->rxlev_nc2_lo = meas_rxlev_nc[1] & 1;
144 mr->rxlev_nc3_hi = meas_rxlev_nc[2] >> 2;
145 mr->rxlev_nc3_lo = meas_rxlev_nc[2] & 3;
146 mr->rxlev_nc4_hi = meas_rxlev_nc[3] >> 3;
147 mr->rxlev_nc4_lo = meas_rxlev_nc[3] & 7;
148 mr->rxlev_nc5_hi = meas_rxlev_nc[4] >> 4;
149 mr->rxlev_nc5_lo = meas_rxlev_nc[4] & 15;
150 mr->rxlev_nc6_hi = meas_rxlev_nc[5] >> 5;
151 mr->rxlev_nc6_lo = meas_rxlev_nc[5] & 31;
152 mr->bsic_nc1_hi = meas_bsic_nc[0] >> 3;
153 mr->bsic_nc1_lo = meas_bsic_nc[0] & 7;
154 mr->bsic_nc2_hi = meas_bsic_nc[1] >> 4;
155 mr->bsic_nc2_lo = meas_bsic_nc[1] & 15;
156 mr->bsic_nc3_hi = meas_bsic_nc[2] >> 5;
157 mr->bsic_nc3_lo = meas_bsic_nc[2] & 31;
158 mr->bsic_nc4 = meas_bsic_nc[3];
159 mr->bsic_nc5 = meas_bsic_nc[4];
160 mr->bsic_nc6 = meas_bsic_nc[5];
161 mr->bcch_f_nc1 = meas_bcch_f_nc[0];
162 mr->bcch_f_nc2 = meas_bcch_f_nc[1];
163 mr->bcch_f_nc3 = meas_bcch_f_nc[2];
164 mr->bcch_f_nc4 = meas_bcch_f_nc[3];
165 mr->bcch_f_nc5_hi = meas_bcch_f_nc[4] >> 1;
166 mr->bcch_f_nc5_lo = meas_bcch_f_nc[4] & 1;
167 mr->bcch_f_nc6_hi = meas_bcch_f_nc[5] >> 2;
168 mr->bcch_f_nc6_lo = meas_bcch_f_nc[5] & 3;
169
170 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
171 msg->l2h = (unsigned char *)dh;
172 msg->l3h = (unsigned char *)gh;
173
174 abis_rsl_rcvmsg(msg);
175}
176
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100177enum gsm_phys_chan_config pchan_from_str(const char *str)
178{
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +0100179 enum gsm_phys_chan_config pchan;
180 if (!strcmp(str, "dyn"))
181 return GSM_PCHAN_TCH_F_TCH_H_PDCH;
182 if (!strcmp(str, "c+s4"))
183 return GSM_PCHAN_CCCH_SDCCH4;
184 if (!strcmp(str, "-"))
185 return GSM_PCHAN_NONE;
186 pchan = gsm_pchan_parse(str);
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100187 if (pchan < 0) {
188 fprintf(stderr, "Invalid timeslot pchan type: %s\n", str);
189 exit(1);
190 }
191 return pchan;
192}
193
194const char * const bts_default_ts[] = {
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +0100195 "c+s4", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H", "TCH/H", "-",
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100196};
197
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100198static struct gsm_bts *create_bts(int num_trx, const char * const *ts_args)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100199{
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100200 static int arfcn = 870;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100201 struct gsm_bts *bts;
202 struct e1inp_sign_link *rsl_link;
203 int i;
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100204 int trx_i;
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100205 struct gsm_bts_trx *trx;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100206
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +0100207 fprintf(stderr, "- Creating BTS %d, %d TRX\n", bsc_gsmnet->num_bts, num_trx);
208 for (trx_i = 0; trx_i < num_trx; trx_i++) {
209 for (i = 0; i < 8; i++)
210 fprintf(stderr, "\t%s", ts_args[8*trx_i + i]);
211 fprintf(stderr, "\n");
212 }
213
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +0700214 bts = bsc_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_UNKNOWN, 0x3f);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100215 if (!bts) {
216 printf("No resource for bts1\n");
217 return NULL;
218 }
219
220 bts->location_area_code = 23;
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100221 bts->c0->arfcn = arfcn++;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100222
223 bts->codec.efr = 1;
224 bts->codec.hr = 1;
225 bts->codec.amr = 1;
226
Neels Hofmeyre3416182018-03-05 05:31:14 +0100227 rsl_link = talloc_zero(ctx, struct e1inp_sign_link);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100228 rsl_link->trx = bts->c0;
229 bts->c0->rsl_link = rsl_link;
230
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100231 for (trx_i = 0; trx_i < num_trx; trx_i++) {
232 while (!(trx = gsm_bts_trx_num(bts, trx_i)))
233 gsm_bts_trx_alloc(bts);
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100234
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100235 trx->mo.nm_state.operational = NM_OPSTATE_ENABLED;
236 trx->mo.nm_state.availability = NM_AVSTATE_OK;
237 trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;
238 trx->bb_transc.mo.nm_state.operational = NM_OPSTATE_ENABLED;
239 trx->bb_transc.mo.nm_state.availability = NM_AVSTATE_OK;
240 trx->bb_transc.mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100241
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100242 /* 4 full rate and 4 half rate channels */
243 for (i = 0; i < 8; i++) {
244 trx->ts[i].pchan_from_config = pchan_from_str(ts_args[trx_i * 8 + i]);
245 if (trx->ts[i].pchan_from_config == GSM_PCHAN_NONE)
246 continue;
247 trx->ts[i].mo.nm_state.operational = NM_OPSTATE_ENABLED;
248 trx->ts[i].mo.nm_state.availability = NM_AVSTATE_OK;
249 trx->ts[i].mo.nm_state.administrative = NM_STATE_UNLOCKED;
250 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200251
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +0100252 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100253 /* make sure ts->lchans[] get initialized */
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +0100254 osmo_fsm_inst_dispatch(trx->ts[i].fi, TS_EV_RSL_READY, 0);
255 osmo_fsm_inst_dispatch(trx->ts[i].fi, TS_EV_OML_READY, 0);
256
257 /* Unused dyn TS start out as used for PDCH */
258 switch (trx->ts[i].pchan_on_init) {
259 case GSM_PCHAN_TCH_F_TCH_H_PDCH:
260 case GSM_PCHAN_TCH_F_PDCH:
261 trx->ts[i].pchan_is = GSM_PCHAN_PDCH;
262 break;
263 default:
264 break;
265 }
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100266 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100267 }
Neels Hofmeyr780f0282020-11-12 22:51:58 +0100268
269 for (i = 0; i < bsc_gsmnet->num_bts; i++) {
270 if (gsm_generate_si(gsm_bts_num(bsc_gsmnet, i), SYSINFO_TYPE_2) <= 0)
271 fprintf(stderr, "Error generating SI2\n");
272 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100273 return bts;
274}
275
276void create_conn(struct gsm_lchan *lchan)
277{
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200278 static unsigned int next_imsi = 0;
279 char imsi[sizeof(lchan->conn->bsub->imsi)];
280 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Welte3561bd42018-01-28 03:04:16 +0100281 struct gsm_subscriber_connection *conn;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200282 struct mgcp_client *fake_mgcp_client = (void*)talloc_zero(net, int);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200283
284 conn = bsc_subscr_con_allocate(net);
Harald Welte3561bd42018-01-28 03:04:16 +0100285
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200286 conn->user_plane.mgw_endpoint = osmo_mgcpc_ep_alloc(conn->fi,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200287 GSCON_EV_FORGET_MGW_ENDPOINT,
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200288 fake_mgcp_client,
289 net->mgw.tdefs,
290 "test",
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200291 "fake endpoint");
Alexander Chemeris69ba8be2020-05-10 22:48:01 +0300292 conn->sccp.msc = osmo_msc_data_alloc(net, 0);
Harald Welte3561bd42018-01-28 03:04:16 +0100293
294 lchan->conn = conn;
295 conn->lchan = lchan;
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200296
297 /* Make up a new IMSI for this test, for logging the subscriber */
298 next_imsi ++;
299 snprintf(imsi, sizeof(imsi), "%06u", next_imsi);
Neels Hofmeyr86a1dca2020-09-15 01:03:58 +0000300 lchan->conn->bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers, imsi, BSUB_USE_CONN);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200301
Harald Welte3561bd42018-01-28 03:04:16 +0100302 /* kick the FSM from INIT through to the ACTIVE state */
Neels Hofmeyrd1e7d392020-09-27 23:34:57 +0200303 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MO_COMPL_L3, NULL);
Harald Welte3561bd42018-01-28 03:04:16 +0100304 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100305}
306
307/* create lchan */
308struct gsm_lchan *create_lchan(struct gsm_bts *bts, int full_rate, char *codec)
309{
310 struct gsm_lchan *lchan;
311
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200312 lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100313 if (!lchan) {
314 printf("No resource for lchan\n");
315 exit(EXIT_FAILURE);
316 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200317
318 /* serious hack into osmo_fsm */
319 lchan->fi->state = LCHAN_ST_ESTABLISHED;
320 lchan->ts->fi->state = TS_ST_IN_USE;
321 LOG_LCHAN(lchan, LOGL_DEBUG, "activated by handover_test.c\n");
322
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100323 create_conn(lchan);
324 if (!strcasecmp(codec, "FR") && full_rate)
325 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
326 else if (!strcasecmp(codec, "HR") && !full_rate)
327 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
328 else if (!strcasecmp(codec, "EFR") && full_rate)
329 lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100330 else if (!strcasecmp(codec, "AMR")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100331 lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100332 lchan->activate.info.s15_s0 = 0x0002;
333 } else {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100334 printf("Given codec unknown\n");
335 exit(EXIT_FAILURE);
336 }
337
338 lchan->conn->codec_list = (struct gsm0808_speech_codec_list){
339 .codec = {
340 { .fi=true, .type=GSM0808_SCT_FR1, },
341 { .fi=true, .type=GSM0808_SCT_FR2, },
342 { .fi=true, .type=GSM0808_SCT_FR3, },
343 { .fi=true, .type=GSM0808_SCT_HR1, },
344 { .fi=true, .type=GSM0808_SCT_HR3, },
345 },
346 .len = 5,
347 };
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100348
349 return lchan;
350}
351
352/* parse channel request */
353
354static int got_chan_req = 0;
355static struct gsm_lchan *chan_req_lchan = NULL;
356
357static int parse_chan_act(struct gsm_lchan *lchan, uint8_t *data)
358{
359 chan_req_lchan = lchan;
360 return 0;
361}
362
363static int parse_chan_rel(struct gsm_lchan *lchan, uint8_t *data)
364{
365 chan_req_lchan = lchan;
366 return 0;
367}
368
369/* parse handover request */
370
371static int got_ho_req = 0;
372static struct gsm_lchan *ho_req_lchan = NULL;
373
374static int parse_ho_command(struct gsm_lchan *lchan, uint8_t *data, int len)
375{
376 struct gsm48_hdr *gh = (struct gsm48_hdr *) data;
377 struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) gh->data;
378 int arfcn;
379 struct gsm_bts *neigh;
380
381 switch (gh->msg_type) {
382 case GSM48_MT_RR_HANDO_CMD:
383 arfcn = (ho->cell_desc.arfcn_hi << 8) | ho->cell_desc.arfcn_lo;
384
385 /* look up trx. since every dummy bts uses different arfcn and
386 * only one trx, it is simple */
387 llist_for_each_entry(neigh, &bsc_gsmnet->bts_list, list) {
388 if (neigh->c0->arfcn != arfcn)
389 continue;
390 ho_req_lchan = lchan;
391 return 0;
392 }
393 break;
394 case GSM48_MT_RR_ASS_CMD:
395 ho_req_lchan = lchan;
396 return 0;
397 break;
398 default:
399 fprintf(stderr, "Error, expecting HO or AS command\n");
400 return -EINVAL;
401 }
402
403 return -1;
404}
405
406/* send channel activation ack */
407static void send_chan_act_ack(struct gsm_lchan *lchan, int act)
408{
409 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
410 struct abis_rsl_dchan_hdr *dh;
411
412 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
413 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
414 dh->c.msg_type = (act) ? RSL_MT_CHAN_ACTIV_ACK : RSL_MT_RF_CHAN_REL_ACK;
415 dh->ie_chan = RSL_IE_CHAN_NR;
416 dh->chan_nr = gsm_lchan2chan_nr(lchan);
417
418 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
419 msg->l2h = (unsigned char *)dh;
420
421 abis_rsl_rcvmsg(msg);
422}
423
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200424/* Send RLL Est Ind for SAPI[0] */
425static void send_est_ind(struct gsm_lchan *lchan)
426{
427 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
428 struct abis_rsl_rll_hdr *rh;
429 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
430
431 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
432 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
433 rh->c.msg_type = RSL_MT_EST_IND;
434 rh->ie_chan = RSL_IE_CHAN_NR;
435 rh->chan_nr = chan_nr;
436 rh->ie_link_id = RSL_IE_LINK_IDENT;
437 rh->link_id = 0x00;
438
439 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
440 msg->l2h = (unsigned char *)rh;
441
442 abis_rsl_rcvmsg(msg);
443}
444
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100445/* send handover complete */
446static void send_ho_complete(struct gsm_lchan *lchan, bool success)
447{
448 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
449 struct abis_rsl_rll_hdr *rh;
450 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
451 uint8_t *buf;
452 struct gsm48_hdr *gh;
453 struct gsm48_ho_cpl *hc;
454
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200455 send_est_ind(lchan);
Neels Hofmeyrac85b342018-07-12 21:23:26 +0200456 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RTP_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200457
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100458 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
459 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
460 rh->c.msg_type = RSL_MT_DATA_IND;
461 rh->ie_chan = RSL_IE_CHAN_NR;
462 rh->chan_nr = chan_nr;
463 rh->ie_link_id = RSL_IE_LINK_IDENT;
464 rh->link_id = 0x00;
465
466 buf = msgb_put(msg, 3);
467 buf[0] = RSL_IE_L3_INFO;
468 buf[1] = (sizeof(*gh) + sizeof(*hc)) >> 8;
469 buf[2] = (sizeof(*gh) + sizeof(*hc)) & 0xff;
470
471 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
472 hc = (struct gsm48_ho_cpl *) msgb_put(msg, sizeof(*hc));
473
474 gh->proto_discr = GSM48_PDISC_RR;
475 gh->msg_type =
476 success ? GSM48_MT_RR_HANDO_COMPL : GSM48_MT_RR_HANDO_FAIL;
477
478 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
479 msg->l2h = (unsigned char *)rh;
480 msg->l3h = (unsigned char *)gh;
481
482 abis_rsl_rcvmsg(msg);
483}
484
Neels Hofmeyr1d7473c2018-03-05 21:53:18 +0100485/* override, requires '-Wl,--wrap=abis_rsl_sendmsg'.
486 * Catch RSL messages sent towards the BTS. */
487int __real_abis_rsl_sendmsg(struct msgb *msg);
488int __wrap_abis_rsl_sendmsg(struct msgb *msg)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100489{
490 struct abis_rsl_dchan_hdr *dh = (struct abis_rsl_dchan_hdr *) msg->data;
491 struct e1inp_sign_link *sign_link = msg->dst;
492 int rc;
493 struct gsm_lchan *lchan = rsl_lchan_lookup(sign_link->trx, dh->chan_nr, &rc);
494
495 if (rc) {
496 printf("rsl_lchan_lookup() failed\n");
497 exit(1);
498 }
499
500 switch (dh->c.msg_type) {
501 case RSL_MT_CHAN_ACTIV:
502 rc = parse_chan_act(lchan, dh->data);
503 if (rc == 0)
504 got_chan_req = 1;
505 break;
506 case RSL_MT_RF_CHAN_REL:
507 rc = parse_chan_rel(lchan, dh->data);
508 if (rc == 0)
509 send_chan_act_ack(chan_req_lchan, 0);
510 break;
511 case RSL_MT_DATA_REQ:
512 rc = parse_ho_command(lchan, msg->l3h, msgb_l3len(msg));
513 if (rc == 0)
514 got_ho_req = 1;
515 break;
516 case RSL_MT_IPAC_CRCX:
517 break;
Neels Hofmeyr5b1a7d12018-11-06 22:24:07 +0100518 case RSL_MT_DEACTIVATE_SACCH:
519 break;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100520 default:
521 printf("unknown rsl message=0x%x\n", dh->c.msg_type);
522 }
523 return 0;
524}
525
526/* test cases */
527
528static char *test_case_0[] = {
529 "2",
530
531 "Stay in better cell\n\n"
532 "There are many neighbor cells, but only the current cell is the best\n"
533 "cell, so no handover is performed\n",
534
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100535 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100536 "create-ms", "0", "TCH/F", "AMR",
537 "meas-rep", "0", "30","0",
538 "6","0","20","1","21","2","18","3","20","4","23","5","19",
539 "expect-no-chan",
540 NULL
541};
542
543static char *test_case_1[] = {
544 "2",
545
546 "Handover to best better cell\n\n"
547 "The best neighbor cell is selected\n",
548
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100549 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100550 "create-ms", "0", "TCH/F", "AMR",
551 "meas-rep", "0", "10","0",
552 "6","0","20","1","21","2","18","3","20","4","23","5","19",
553 "expect-chan", "5", "1",
554 "ack-chan",
555 "expect-ho", "0", "1",
556 "ho-complete",
557 NULL
558};
559
560static char *test_case_2[] = {
561 "2",
562
563 "Handover and Assignment must be enabled\n\n"
564 "This test will start with disabled assignment and handover. A\n"
565 "better neighbor cell (assignment enabled) will not be selected and \n"
566 "also no assignment from TCH/H to TCH/F to improve quality. There\n"
567 "will be no handover nor assignment. After enabling assignment on the\n"
568 "current cell, the MS will assign to TCH/F. After enabling handover\n"
569 "in the current cell, but disabling in the neighbor cell, handover\n"
570 "will not be performed, until it is enabled in the neighbor cell too.\n",
571
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100572 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100573 "afs-rxlev-improve", "0", "5",
574 "create-ms", "0", "TCH/H", "AMR",
575 "as-enable", "0", "0",
576 "ho-enable", "0", "0",
577 "meas-rep", "0", "0","0", "1","0","30",
578 "expect-no-chan",
579 "as-enable", "0", "1",
580 "meas-rep", "0", "0","0", "1","0","30",
581 "expect-chan", "0", "1",
582 "ack-chan",
583 "expect-ho", "0", "5",
584 "ho-complete",
585 "ho-enable", "0", "1",
586 "ho-enable", "1", "0",
587 "meas-rep", "0", "0","0", "1","0","30",
588 "expect-no-chan",
589 "ho-enable", "1", "1",
590 "meas-rep", "0", "0","0", "1","0","30",
591 "expect-chan", "1", "1",
592 "ack-chan",
593 "expect-ho", "0", "1",
594 "ho-complete",
595 NULL
596};
597
598static char *test_case_3[] = {
599 "2",
600
601 "Penalty timer must not run\n\n"
602 "The MS will try to handover to a better cell, but this will fail.\n"
603 "Even though the cell is still better, handover will not be performed\n"
604 "due to penalty timer after handover failure\n",
605
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100606 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100607 "create-ms", "0", "TCH/F", "AMR",
608 "meas-rep", "0", "20","0", "1","0","30",
609 "expect-chan", "1", "1",
610 "ack-chan",
611 "expect-ho", "0", "1",
612 "ho-failed",
613 "meas-rep", "0", "20","0", "1","0","30",
614 "expect-no-chan",
615 NULL
616};
617
618static char *test_case_4[] = {
619 "2",
620
621 "TCH/H keeping with HR codec\n\n"
622 "The MS is using half rate V1 codec, but the better cell is congested\n"
623 "at TCH/H slots. As the congestion is removed, the handover takes\n"
624 "place.\n",
625
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100626 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100627 "set-min-free", "1", "TCH/H", "4",
628 "create-ms", "0", "TCH/H", "HR",
629 "meas-rep", "0", "20","0", "1","0","30",
630 "expect-no-chan",
631 "set-min-free", "1", "TCH/H", "3",
632 "meas-rep", "0", "20","0", "1","0","30",
633 "expect-chan", "1", "5",
634 "ack-chan",
635 "expect-ho", "0", "5",
636 "ho-complete",
637 NULL
638};
639
640static char *test_case_5[] = {
641 "2",
642
643 "TCH/F keeping with FR codec\n\n"
644 "The MS is using full rate V1 codec, but the better cell is congested\n"
645 "at TCH/F slots. As the congestion is removed, the handover takes\n"
646 "place.\n",
647
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100648 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100649 "set-min-free", "1", "TCH/F", "4",
650 "create-ms", "0", "TCH/F", "FR",
651 "meas-rep", "0", "20","0", "1","0","30",
652 "expect-no-chan",
653 "set-min-free", "1", "TCH/F", "3",
654 "meas-rep", "0", "20","0", "1","0","30",
655 "expect-chan", "1", "1",
656 "ack-chan",
657 "expect-ho", "0", "1",
658 "ho-complete",
659 NULL
660};
661
662static char *test_case_6[] = {
663 "2",
664
665 "TCH/F keeping with EFR codec\n\n"
666 "The MS is using full rate V2 codec, but the better cell is congested\n"
667 "at TCH/F slots. As the congestion is removed, the handover takes\n"
668 "place.\n",
669
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100670 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100671 "set-min-free", "1", "TCH/F", "4",
672 "create-ms", "0", "TCH/F", "EFR",
673 "meas-rep", "0", "20","0", "1","0","30",
674 "expect-no-chan",
675 "set-min-free", "1", "TCH/F", "3",
676 "meas-rep", "0", "20","0", "1","0","30",
677 "expect-chan", "1", "1",
678 "ack-chan",
679 "expect-ho", "0", "1",
680 "ho-complete",
681 NULL
682};
683
684static char *test_case_7[] = {
685 "2",
686
687 "TCH/F to TCH/H changing with AMR codec\n\n"
688 "The MS is using AMR V3 codec, the better cell is congested at TCH/F\n"
689 "slots. The handover is performed to non-congested TCH/H slots.\n",
690
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100691 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100692 "set-min-free", "1", "TCH/F", "4",
693 "create-ms", "0", "TCH/F", "AMR",
694 "meas-rep", "0", "20","0", "1","0","30",
695 "expect-chan", "1", "5",
696 "ack-chan",
697 "expect-ho", "0", "1",
698 "ho-complete",
699 NULL
700};
701
702static char *test_case_8[] = {
703 "2",
704
705 "No handover to a cell with no slots available\n\n"
706 "If no slot is available, no handover is performed\n",
707
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100708 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100709 "create-ms", "0", "TCH/F", "AMR",
710 "create-ms", "1", "TCH/F", "AMR",
711 "create-ms", "1", "TCH/F", "AMR",
712 "create-ms", "1", "TCH/F", "AMR",
713 "create-ms", "1", "TCH/F", "AMR",
714 "create-ms", "1", "TCH/H", "AMR",
715 "create-ms", "1", "TCH/H", "AMR",
716 "create-ms", "1", "TCH/H", "AMR",
717 "create-ms", "1", "TCH/H", "AMR",
718 "meas-rep", "0", "0","0", "1","0","30",
719 "expect-no-chan",
720 NULL
721};
722
723static char *test_case_9[] = {
724 "2",
725
726 "No more parallel handovers, if max_unsync_ho is defined\n\n"
727 "There are tree mobiles that want to handover, but only two can do\n"
728 "it at a time, because the maximum number is limited to two.\n",
729
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100730 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100731 "set-max-ho", "1", "2",
732 "create-ms", "0", "TCH/F", "AMR",
733 "create-ms", "0", "TCH/F", "AMR",
734 "create-ms", "0", "TCH/F", "AMR",
735 "meas-rep", "0", "0","0", "1","0","30",
736 "expect-chan", "1", "1",
737 "meas-rep", "1", "0","0", "1","0","30",
738 "expect-chan", "1", "2",
739 "meas-rep", "2", "0","0", "1","0","30",
740 "expect-no-chan",
741 NULL
742};
743
744static char *test_case_10[] = {
745 "2",
746
747 "Hysteresis\n\n"
748 "If neighbor cell is better, handover is only performed if the\n"
Martin Haukea29affd2019-11-13 22:10:41 +0100749 "amount of improvement is greater or equal hyteresis\n",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100750
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100751 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100752 "create-ms", "0", "TCH/F", "AMR",
753 "meas-rep", "0", "27","0", "1","0","30",
754 "expect-no-chan",
755 "meas-rep", "0", "26","0", "1","0","30",
756 "expect-chan", "1", "1",
757 "ack-chan",
758 "expect-ho", "0", "1",
759 "ho-complete",
760 NULL
761};
762
763static char *test_case_11[] = {
764 "2",
765
766 "No Hysteresis and minimum RX level\n\n"
767 "If current cell's RX level is below mimium level, handover must be\n"
768 "performed, no matter of the hysteresis. First do not perform\n"
769 "handover to better neighbor cell, because the hysteresis is not\n"
770 "met. Second do not perform handover because better neighbor cell is\n"
771 "below minimum RX level. Third perform handover because current cell\n"
772 "is below minimum RX level, even if the better neighbor cell (minimum\n"
773 "RX level reached) does not meet the hysteresis.\n",
774
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100775 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100776 "create-ms", "0", "TCH/F", "AMR",
777 "meas-rep", "0", "10","0", "1","0","11",
778 "expect-no-chan",
779 "meas-rep", "0", "8","0", "1","0","9",
780 "expect-no-chan",
781 "meas-rep", "0", "9","0", "1","0","10",
782 "expect-chan", "1", "1",
783 "ack-chan",
784 "expect-ho", "0", "1",
785 "ho-complete",
786 NULL
787};
788
789static char *test_case_12[] = {
790 "2",
791
792 "No handover to congested cell\n\n"
793 "The better neighbor cell is congested, so no handover is performed.\n"
794 "After the congestion is over, handover will be performed.\n",
795
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100796 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100797 "create-ms", "0", "TCH/F", "AMR",
798 "set-min-free", "1", "TCH/F", "4",
799 "set-min-free", "1", "TCH/H", "4",
800 "meas-rep", "0", "20","0", "1","0","30",
801 "expect-no-chan",
802 "set-min-free", "1", "TCH/F", "3",
803 "set-min-free", "1", "TCH/H", "3",
804 "meas-rep", "0", "20","0", "1","0","30",
805 "expect-chan", "1", "1",
806 "ack-chan",
807 "expect-ho", "0", "1",
808 "ho-complete",
809 NULL
810};
811
812static char *test_case_13[] = {
813 "2",
814
815 "Handover to balance congestion\n\n"
816 "The current and the better cell are congested, so no handover is\n"
817 "performed. This is because handover would congest the neighbor cell\n"
818 "more. After congestion raises in the current cell, the handover is\n"
819 "performed to balance congestion\n",
820
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100821 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100822 "create-ms", "0", "TCH/F", "AMR",
823 "set-min-free", "0", "TCH/F", "4",
824 "set-min-free", "0", "TCH/H", "4",
825 "set-min-free", "1", "TCH/F", "4",
826 "set-min-free", "1", "TCH/H", "4",
827 "meas-rep", "0", "20","0", "1","0","30",
828 "expect-no-chan",
829 "create-ms", "0", "TCH/F", "AMR",
830 "meas-rep", "0", "20","0", "1","0","30",
831 "expect-chan", "1", "1",
832 "ack-chan",
833 "expect-ho", "0", "1",
834 "ho-complete",
835 NULL
836};
837
838static char *test_case_14[] = {
839 "2",
840
841 "Handover to congested cell, if RX level is below minimum\n\n"
842 "The better neighbor cell is congested, so no handover is performed.\n"
843 "If the RX level of the current cell drops below minimum acceptable\n"
844 "level, the handover is performed.\n",
845
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100846 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100847 "create-ms", "0", "TCH/F", "AMR",
848 "set-min-free", "1", "TCH/F", "4",
849 "set-min-free", "1", "TCH/H", "4",
850 "meas-rep", "0", "10","0", "1","0","30",
851 "expect-no-chan",
852 "meas-rep", "0", "9","0", "1","0","30",
853 "expect-chan", "1", "1",
854 "ack-chan",
855 "expect-ho", "0", "1",
856 "ho-complete",
857 NULL
858};
859
860static char *test_case_15[] = {
861 "2",
862
863 "Handover to cell with worse RXLEV, if RXQUAL is below minimum\n\n"
864 "The neighbor cell has worse RXLEV, so no handover is performed.\n"
865 "If the RXQUAL of the current cell drops below minimum acceptable\n"
866 "level, the handover is performed. It is also required that 10\n"
867 "reports are received, before RXQUAL is checked.\n",
868 /* (See also test 28, which tests for RXQUAL triggering HO to congested cell.) */
869 /* TODO: bad RXQUAL may want to prefer assignment within the same cell to avoid interference.
Martin Haukea29affd2019-11-13 22:10:41 +0100870 * See Performance Enhancements in a Frequency Hopping GSM Network (Nielsen Wigard 2002), Chapter
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100871 * 2.1.1, "Interference" in the list of triggers on p.157. */
872
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100873 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100874 "create-ms", "0", "TCH/F", "AMR",
875 "meas-rep", "0", "40","6", "1","0","30",
876 "expect-no-chan",
877 "meas-rep", "0", "40","6", "1","0","30",
878 "expect-no-chan",
879 "meas-rep", "0", "40","6", "1","0","30",
880 "expect-no-chan",
881 "meas-rep", "0", "40","6", "1","0","30",
882 "expect-no-chan",
883 "meas-rep", "0", "40","6", "1","0","30",
884 "expect-no-chan",
885 "meas-rep", "0", "40","6", "1","0","30",
886 "expect-no-chan",
887 "meas-rep", "0", "40","6", "1","0","30",
888 "expect-no-chan",
889 "meas-rep", "0", "40","6", "1","0","30",
890 "expect-no-chan",
891 "meas-rep", "0", "40","6", "1","0","30",
892 "expect-no-chan",
893 "meas-rep", "0", "40","6", "1","0","30",
894 "expect-chan", "1", "1",
895 "ack-chan",
896 "expect-ho", "0", "1",
897 "ho-complete",
898 NULL
899};
900
901static char *test_case_16[] = {
902 "2",
903
904 "Handover due to maximum TA exceeded\n\n"
905 "The MS in the current (best) cell has reached maximum allowed timing\n"
906 "advance. No handover is performed until the timing advance exceeds\n"
907 "it. The originating cell is still the best, but no handover is\n"
908 "performed back to that cell, because the penalty timer (due to\n"
909 "maximum allowed timing advance) is running.\n",
910
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100911 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100912 "create-ms", "0", "TCH/F", "AMR",
913 "set-max-ta", "0", "5", /* of cell */
914 "set-ta", "0", "5", /* of ms */
915 "meas-rep", "0", "30","0", "1","0","20",
916 "expect-no-chan",
917 "set-ta", "0", "6", /* of ms */
918 "meas-rep", "0", "30","0", "1","0","20",
919 "expect-chan", "1", "1",
920 "ack-chan",
921 "expect-ho", "0", "1",
922 "ho-complete",
923 "meas-rep", "0", "20","0", "1","0","30",
924 "expect-no-chan",
925 NULL
926};
927
928static char *test_case_17[] = {
929 "2",
930
931 "Congestion check: No congestion\n\n"
932 "Three cells have different number of used slots, but there is no\n"
933 "congestion in any of these cells. No handover is performed.\n",
934
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100935 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100936 "set-min-free", "0", "TCH/F", "2",
937 "set-min-free", "0", "TCH/H", "2",
938 "set-min-free", "1", "TCH/F", "2",
939 "set-min-free", "1", "TCH/H", "2",
940 "set-min-free", "2", "TCH/F", "2",
941 "set-min-free", "2", "TCH/H", "2",
942 "create-ms", "0", "TCH/F", "AMR",
943 "create-ms", "0", "TCH/F", "AMR",
944 "create-ms", "0", "TCH/H", "AMR",
945 "create-ms", "0", "TCH/H", "AMR",
946 "create-ms", "1", "TCH/F", "AMR",
947 "create-ms", "1", "TCH/H", "AMR",
948 "meas-rep", "0", "30","0", "2","0","20","1","20",
949 "expect-no-chan",
950 "meas-rep", "1", "30","0", "2","0","20","1","20",
951 "expect-no-chan",
952 "meas-rep", "2", "30","0", "2","0","20","1","20",
953 "expect-no-chan",
954 "meas-rep", "3", "30","0", "2","0","20","1","20",
955 "expect-no-chan",
956 "meas-rep", "4", "30","0", "2","0","20","1","20",
957 "expect-no-chan",
958 "meas-rep", "5", "30","0", "2","0","20","1","20",
959 "expect-no-chan",
960 "congestion-check",
961 "expect-no-chan",
962 NULL
963};
964
965static char *test_case_18[] = {
966 "2",
967
968 "Congestion check: One out of three cells is congested\n\n"
969 "Three cells have different number of used slots, but there is\n"
970 "congestion at TCH/F in the first cell. Handover is performed with\n"
971 "the best candidate.\n",
972
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100973 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100974 "set-min-free", "0", "TCH/F", "2",
975 "set-min-free", "0", "TCH/H", "2",
976 "set-min-free", "1", "TCH/F", "2",
977 "set-min-free", "1", "TCH/H", "2",
978 "set-min-free", "2", "TCH/F", "2",
979 "set-min-free", "2", "TCH/H", "2",
980 "create-ms", "0", "TCH/F", "AMR",
981 "create-ms", "0", "TCH/F", "AMR",
982 "create-ms", "0", "TCH/F", "AMR",
983 "create-ms", "0", "TCH/H", "AMR",
984 "create-ms", "0", "TCH/H", "AMR",
985 "create-ms", "1", "TCH/F", "AMR",
986 "create-ms", "1", "TCH/H", "AMR",
987 "meas-rep", "0", "30","0", "2","0","20","1","20",
988 "expect-no-chan",
989 "meas-rep", "1", "30","0", "2","0","20","1","20",
990 "expect-no-chan",
991 "meas-rep", "2", "30","0", "2","0","21","1","20",
992 "expect-no-chan",
993 "meas-rep", "3", "30","0", "2","0","20","1","20",
994 "expect-no-chan",
995 "meas-rep", "4", "30","0", "2","0","20","1","20",
996 "expect-no-chan",
997 "meas-rep", "5", "30","0", "2","0","20","1","20",
998 "expect-no-chan",
999 "meas-rep", "6", "30","0", "2","0","20","1","20",
1000 "expect-no-chan",
1001 "congestion-check",
1002 "expect-chan", "1", "2",
1003 "ack-chan",
Neels Hofmeyr72d64e72020-11-16 18:07:31 +01001004 "expect-ho", "0", "3", /* best candidate is MS 2 at BTS 0, TS 3 */
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001005 "ho-complete",
1006 NULL
1007};
1008
1009static char *test_case_19[] = {
1010 "2",
1011
1012 "Congestion check: Balancing over congested cells\n\n"
Neels Hofmeyr1336d942020-08-10 21:13:55 +02001013 "Two cells are congested, but the second cell is less congested.\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001014 "Handover is performed to solve the congestion.\n",
1015
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001016 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001017 "set-min-free", "0", "TCH/F", "4",
1018 "set-min-free", "1", "TCH/F", "4",
1019 "create-ms", "0", "TCH/F", "FR",
1020 "create-ms", "0", "TCH/F", "FR",
1021 "create-ms", "0", "TCH/F", "FR",
1022 "create-ms", "1", "TCH/F", "FR",
1023 "meas-rep", "0", "30","0", "1","0","20",
1024 "expect-no-chan",
1025 "meas-rep", "1", "30","0", "1","0","21",
1026 "expect-no-chan",
1027 "meas-rep", "2", "30","0", "1","0","20",
1028 "expect-no-chan",
1029 "meas-rep", "3", "30","0", "1","0","20",
1030 "expect-no-chan",
1031 "congestion-check",
1032 "expect-chan", "1", "2",
1033 "ack-chan",
1034 "expect-ho", "0", "2", /* best candidate is MS 1 at BTS 0, TS 2 */
1035 "ho-complete",
1036 NULL
1037};
1038
1039static char *test_case_20[] = {
1040 "2",
1041
1042 "Congestion check: Solving congestion by handover TCH/F -> TCH/H\n\n"
1043 "Two BTS, one MS in the first congested BTS must handover to\n"
1044 "non-congested TCH/H of second BTS, in order to solve congestion\n",
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001045 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001046 "set-min-free", "0", "TCH/F", "4",
1047 "set-min-free", "0", "TCH/H", "4",
1048 "set-min-free", "1", "TCH/F", "4",
1049 "create-ms", "0", "TCH/F", "AMR",
1050 "meas-rep", "0", "30","0", "1","0","30",
1051 "expect-no-chan",
1052 "congestion-check",
1053 "expect-chan", "1", "5",
1054 "ack-chan",
1055 "expect-ho", "0", "1",
1056 "ho-complete",
1057 NULL
1058};
1059
1060static char *test_case_21[] = {
1061 "2",
1062
1063 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1064 "Two BTS, one MS in the first congested BTS must handover to\n"
1065 "less-congested TCH/H of second BTS, in order to balance congestion\n",
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001066 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001067 "set-min-free", "0", "TCH/F", "4",
1068 "set-min-free", "0", "TCH/H", "4",
1069 "set-min-free", "1", "TCH/F", "4",
1070 "set-min-free", "1", "TCH/H", "4",
1071 "create-ms", "0", "TCH/F", "AMR",
1072 "create-ms", "0", "TCH/F", "AMR",
1073 "create-ms", "0", "TCH/H", "AMR",
1074 "meas-rep", "0", "30","0", "1","0","30",
1075 "expect-no-chan",
1076 "congestion-check",
1077 "expect-chan", "1", "1",
1078 "ack-chan",
1079 "expect-ho", "0", "1",
1080 "ho-complete",
1081 NULL
1082};
1083
1084static char *test_case_22[] = {
1085 "2",
1086
1087 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1088 "There is only one BTS. The TCH/H slots are congested. Since\n"
1089 "assignment is performed to less-congested TCH/F, the candidate with\n"
1090 "the worst RX level is chosen.\n",
1091
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001092 "create-n-bts", "1",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001093 "set-min-free", "0", "TCH/F", "4",
1094 "set-min-free", "0", "TCH/H", "4",
1095 "create-ms", "0", "TCH/H", "AMR",
1096 "create-ms", "0", "TCH/H", "AMR",
1097 "create-ms", "0", "TCH/H", "AMR",
1098 "meas-rep", "0", "30","0", "0",
1099 "meas-rep", "1", "34","0", "0",
1100 "meas-rep", "2", "20","0", "0",
1101 "expect-no-chan",
1102 "congestion-check",
1103 "expect-chan", "0", "1",
1104 "ack-chan",
1105 "expect-ho", "0", "6",
1106 "ho-complete",
1107 NULL
1108};
1109
1110static char *test_case_23[] = {
1111 "2",
1112
1113 "Story: 'A neighbor is your friend'\n",
1114
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001115 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001116
1117 "print",
1118 "Andreas is driving along the coast, on a sunny june afternoon.\n"
1119 "Suddenly he is getting a call from his friend and neighbor Axel.\n"
1120 "\n"
1121 "What happens: Two MS are created, #0 for Axel, #1 for Andreas.",
1122 /* Axel */
1123 "create-ms", "2", "TCH/F", "AMR",
1124 /* andreas */
1125 "create-ms", "0", "TCH/F", "AMR",
1126 "meas-rep", "1", "40","0", "1","0","30",
1127 "expect-no-chan",
1128
1129 "print",
1130 "Axel asks Andreas if he would like to join them for a barbecue.\n"
1131 "Axel's house is right in the neighborhood and the weather is fine.\n"
1132 "Andreas agrees, so he drives to a close store to buy some barbecue\n"
1133 "skewers.\n"
1134 "\n"
1135 "What happens: While driving, a different cell (mounted atop the\n"
1136 "store) becomes better.",
1137 /* drive to bts 1 */
1138 "meas-rep", "1", "20","0", "1","0","35",
1139 "expect-chan", "1", "1",
1140 "ack-chan",
1141 "expect-ho", "0", "1",
1142 "ho-complete",
1143
1144 "print",
1145 "While Andreas is walking into the store, Axel asks, if he could also\n"
1146 "bring some beer. Andreas has problems understanding him: \"I have a\n"
1147 "bad reception here. The cell tower is right atop the store, but poor\n"
1148 "coverage inside. Can you repeat please?\"\n"
1149 "\n"
1150 "What happens: Inside the store the close cell is so bad, that\n"
1151 "handover back to the previous cell is required.",
1152 /* bts 1 becomes bad, so bts 0 helps out */
1153 "meas-rep", "1", "5","0", "1","0","20",
1154 "expect-chan", "0", "1",
1155 "ack-chan",
1156 "expect-ho", "1", "1",
1157 "ho-complete",
1158
1159 "print",
1160 "After Andreas bought skewers and beer, he leaves the store.\n"
1161 "\n"
1162 "What happens: Outside the store the close cell is better again, so\n"
1163 "handover back to the that cell is performed.",
1164 /* bts 1 becomes better again */
1165 "meas-rep", "1", "20","0", "1","0","35",
1166 "expect-chan", "1", "1",
1167 "ack-chan",
1168 "expect-ho", "0", "1",
1169 "ho-complete",
1170
1171 "print",
1172 /* bts 2 becomes better */
1173 "Andreas drives down to the lake where Axel's house is.\n"
1174 "\n"
1175 "What happens: There is a small cell at Axel's house, which becomes\n"
1176 "better, because the current cell has no good comverage at the lake.",
1177 "meas-rep", "1", "14","0", "2","0","2","1","63",
1178 "expect-chan", "2", "2",
1179 "ack-chan",
1180 "expect-ho", "1", "1",
1181 "ho-complete",
1182
1183 "print",
1184 "Andreas wonders why he still has good radio coverage: \"Last time it\n"
1185 "was so bad\". Axel says: \"I installed a pico cell in my house,\n"
1186 "now we can use our mobile phones down here at the lake.\"",
1187
1188 NULL
1189};
1190
1191static char *test_case_24[] = {
1192 "2",
1193 "No (or not enough) measurements for handover\n\n"
1194 "Do not solve congestion in cell, because there is no measurement.\n"
Martin Haukea29affd2019-11-13 22:10:41 +01001195 "As soon as enough measurements available (1 in our case), perform\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001196 "handover. Afterwards the old cell becomes congested and the new\n"
1197 "cell is not. Do not perform handover until new measurements are\n"
1198 "received.\n",
1199
1200 /* two cells, first in congested, but no handover */
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001201 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001202 "set-min-free", "0", "TCH/F", "4",
1203 "set-min-free", "0", "TCH/H", "4",
1204 "create-ms", "0", "TCH/F", "AMR",
1205 "congestion-check",
1206 "expect-no-chan",
1207
1208 /* send measurement and trigger congestion check */
1209 "meas-rep", "0", "20","0", "1","0","20",
1210 "expect-no-chan",
1211 "congestion-check",
1212 "expect-chan", "1", "1",
1213 "ack-chan",
1214 "expect-ho", "0", "1",
1215 "ho-complete",
1216
1217 /* congest the first cell and remove congestion from second cell */
1218 "set-min-free", "0", "TCH/F", "0",
1219 "set-min-free", "0", "TCH/H", "0",
1220 "set-min-free", "1", "TCH/F", "4",
1221 "set-min-free", "1", "TCH/H", "4",
1222
1223 /* no handover until measurements applied */
1224 "congestion-check",
1225 "expect-no-chan",
1226 "meas-rep", "0", "20","0", "1","0","20",
1227 "expect-no-chan",
1228 "congestion-check",
1229 "expect-chan", "0", "1",
1230 "ack-chan",
1231 "expect-ho", "1", "1",
1232 "ho-complete",
1233 NULL
1234};
1235
1236static char *test_case_25[] = {
1237 "1",
1238
1239 "Stay in better cell\n\n"
1240 "There are many neighbor cells, but only the current cell is the best\n"
1241 "cell, so no handover is performed\n",
1242
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001243 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001244 "create-ms", "0", "TCH/F", "AMR",
1245 "meas-rep", "0", "30","0",
1246 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1247 "expect-no-chan",
1248 NULL
1249};
1250
1251static char *test_case_26[] = {
1252 "1",
1253
1254 "Handover to best better cell\n\n"
1255 "The best neighbor cell is selected\n",
1256
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001257 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001258 "create-ms", "0", "TCH/F", "AMR",
1259 "meas-rep", "0", "10","0",
1260 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1261 "expect-chan", "5", "1",
1262 "ack-chan",
1263 "expect-ho", "0", "1",
1264 "ho-complete",
1265 NULL
1266};
1267
1268static char *test_case_27[] = {
1269 "2",
1270
1271 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1272 "There is only one BTS. The TCH/H slots are congested. Since\n"
1273 "assignment is performed to less-congested TCH/F, the candidate with\n"
1274 "the worst RX level is chosen. (So far like test 22.)\n"
1275 "After that, trigger more congestion checks to ensure stability.\n",
1276
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001277 "create-n-bts", "1",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001278 "set-min-free", "0", "TCH/F", "2",
1279 "set-min-free", "0", "TCH/H", "4",
1280 "create-ms", "0", "TCH/H", "AMR",
1281 "create-ms", "0", "TCH/H", "AMR",
1282 "create-ms", "0", "TCH/H", "AMR",
1283 "meas-rep", "0", "30","0", "0",
1284 "meas-rep", "1", "34","0", "0",
1285 "meas-rep", "2", "20","0", "0",
1286 "expect-no-chan",
1287 "congestion-check",
1288 "expect-chan", "0", "1",
1289 "ack-chan",
1290 "expect-ho", "0", "6",
1291 "ho-complete",
1292 "congestion-check",
1293 "expect-chan", "0", "2",
1294 "ack-chan",
1295 "expect-ho", "0", "5",
1296 "ho-complete",
1297 "congestion-check",
1298 "expect-no-chan",
1299 "congestion-check",
1300 "expect-no-chan",
1301 NULL
1302};
1303
1304static char *test_case_28[] = {
1305 "2",
1306
1307 "Handover to congested cell, if RX quality is below minimum\n\n"
1308 "The better neighbor cell is congested, so no handover is performed.\n"
1309 "If the RX quality of the current cell drops below minimum acceptable\n"
1310 "level, the handover is performed. It is also required that 10\n"
1311 "resports are received, before RX quality is checked.\n",
1312
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001313 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001314 "create-ms", "0", "TCH/F", "AMR",
1315 "set-min-free", "1", "TCH/F", "4",
1316 "set-min-free", "1", "TCH/H", "4",
1317 "meas-rep", "0", "30","6", "1","0","40",
1318 "expect-no-chan",
1319 "meas-rep", "0", "30","6", "1","0","40",
1320 "expect-no-chan",
1321 "meas-rep", "0", "30","6", "1","0","40",
1322 "expect-no-chan",
1323 "meas-rep", "0", "30","6", "1","0","40",
1324 "expect-no-chan",
1325 "meas-rep", "0", "30","6", "1","0","40",
1326 "expect-no-chan",
1327 "meas-rep", "0", "30","6", "1","0","40",
1328 "expect-no-chan",
1329 "meas-rep", "0", "30","6", "1","0","40",
1330 "expect-no-chan",
1331 "meas-rep", "0", "30","6", "1","0","40",
1332 "expect-no-chan",
1333 "meas-rep", "0", "30","6", "1","0","40",
1334 "expect-no-chan",
1335 "meas-rep", "0", "30","6", "1","0","40",
1336 "expect-chan", "1", "1",
1337 "ack-chan",
1338 "expect-ho", "0", "1",
1339 "ho-complete",
1340 NULL
1341};
1342
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001343static char *test_case_29[] = {
1344 "2",
1345
1346 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1347 "One BTS, and TCH/F are considered congested, TCH/H are not.\n"
1348 ,
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001349 "create-n-bts", "1",
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001350 "set-min-free", "0", "TCH/F", "3",
1351 "set-min-free", "0", "TCH/H", "0",
1352 "create-ms", "0", "TCH/F", "AMR",
1353 "create-ms", "0", "TCH/F", "AMR",
1354 "create-ms", "0", "TCH/H", "AMR",
1355 "meas-rep", "0", "30","0", "1","0","30",
1356 "expect-no-chan",
1357 "congestion-check",
1358 "expect-chan", "0", "5",
1359 "ack-chan",
1360 "expect-ho", "0", "1",
1361 "ho-complete",
1362 NULL
1363};
1364
1365
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001366static char **test_cases[] = {
1367 test_case_0,
1368 test_case_1,
1369 test_case_2,
1370 test_case_3,
1371 test_case_4,
1372 test_case_5,
1373 test_case_6,
1374 test_case_7,
1375 test_case_8,
1376 test_case_9,
1377 test_case_10,
1378 test_case_11,
1379 test_case_12,
1380 test_case_13,
1381 test_case_14,
1382 test_case_15,
1383 test_case_16,
1384 test_case_17,
1385 test_case_18,
1386 test_case_19,
1387 test_case_20,
1388 test_case_21,
1389 test_case_22,
1390 test_case_23,
1391 test_case_24,
1392 test_case_25,
1393 test_case_26,
1394 test_case_27,
1395 test_case_28,
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001396 test_case_29,
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001397};
1398
1399static const struct log_info_cat log_categories[] = {
1400 [DHO] = {
1401 .name = "DHO",
1402 .description = "Hand-Over Process",
1403 .color = "\033[1;38m",
1404 .enabled = 1, .loglevel = LOGL_DEBUG,
1405 },
1406 [DHODEC] = {
1407 .name = "DHODEC",
1408 .description = "Hand-Over Decision",
1409 .color = "\033[1;38m",
1410 .enabled = 1, .loglevel = LOGL_DEBUG,
1411 },
1412 [DMEAS] = {
1413 .name = "DMEAS",
1414 .description = "Radio Measurement Processing",
1415 .enabled = 1, .loglevel = LOGL_DEBUG,
1416 },
1417 [DREF] = {
1418 .name = "DREF",
1419 .description = "Reference Counting",
1420 .enabled = 1, .loglevel = LOGL_DEBUG,
1421 },
1422 [DRSL] = {
1423 .name = "DRSL",
Keithd925c7c2018-04-16 13:40:07 +02001424 .description = "A-bis Radio Signalling Link (RSL)",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001425 .color = "\033[1;35m",
1426 .enabled = 1, .loglevel = LOGL_DEBUG,
1427 },
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001428 [DRR] = {
1429 .name = "DRR",
1430 .description = "RR",
1431 .color = "\033[1;35m",
1432 .enabled = 1, .loglevel = LOGL_DEBUG,
1433 },
1434 [DRLL] = {
1435 .name = "DRLL",
1436 .description = "RLL",
1437 .color = "\033[1;35m",
1438 .enabled = 1, .loglevel = LOGL_DEBUG,
1439 },
Harald Welte3561bd42018-01-28 03:04:16 +01001440 [DMSC] = {
1441 .name = "DMSC",
1442 .description = "Mobile Switching Center",
1443 .enabled = 1, .loglevel = LOGL_DEBUG,
1444 },
Neels Hofmeyr3c5612f2018-07-11 19:53:39 +02001445 [DCHAN] = {
1446 .name = "DCHAN",
1447 .description = "lchan FSM",
1448 .color = "\033[1;32m",
1449 .enabled = 1, .loglevel = LOGL_DEBUG,
1450 },
1451 [DTS] = {
1452 .name = "DTS",
1453 .description = "timeslot FSM",
1454 .color = "\033[1;31m",
1455 .enabled = 1, .loglevel = LOGL_DEBUG,
1456 },
1457 [DAS] = {
1458 .name = "DAS",
1459 .description = "assignment FSM",
1460 .color = "\033[1;33m",
1461 .enabled = 1, .loglevel = LOGL_DEBUG,
1462 },
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001463};
1464
1465const struct log_info log_info = {
1466 .cat = log_categories,
1467 .num_cat = ARRAY_SIZE(log_categories),
1468};
1469
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001470struct gsm_bts *bts_by_num_str(const char *num_str)
1471{
1472 struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, atoi(num_str));
1473 OSMO_ASSERT(bts);
1474 return bts;
1475}
1476
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001477int main(int argc, char **argv)
1478{
1479 char **test_case;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001480 struct gsm_lchan *lchan[256];
1481 int lchan_num = 0;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001482 int i;
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001483 int algorithm;
Neels Hofmeyr00727552018-02-21 14:33:15 +01001484 int test_case_i;
1485 int last_test_i;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001486
Neels Hofmeyre3416182018-03-05 05:31:14 +01001487 ctx = talloc_named_const(NULL, 0, "handover_test");
1488 msgb_talloc_ctx_init(ctx, 0);
1489
Neels Hofmeyr00727552018-02-21 14:33:15 +01001490 test_case_i = argc > 1? atoi(argv[1]) : -1;
1491 last_test_i = ARRAY_SIZE(test_cases) - 1;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001492
Neels Hofmeyr00727552018-02-21 14:33:15 +01001493 if (test_case_i < 0 || test_case_i > last_test_i) {
1494 for (i = 0; i <= last_test_i; i++) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001495 printf("Test #%d (algorithm %s):\n%s\n", i,
1496 test_cases[i][0], test_cases[i][1]);
1497 }
Neels Hofmeyr00727552018-02-21 14:33:15 +01001498 printf("\nPlease specify test case number 0..%d\n", last_test_i);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001499 return EXIT_FAILURE;
1500 }
1501
Neels Hofmeyre3416182018-03-05 05:31:14 +01001502 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001503
1504 log_set_print_category(osmo_stderr_target, 1);
1505 log_set_print_category_hex(osmo_stderr_target, 0);
1506 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001507 osmo_fsm_log_addr(false);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001508
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001509 bsc_network_alloc();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001510 if (!bsc_gsmnet)
1511 exit(1);
1512
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001513 ts_fsm_init();
1514 lchan_fsm_init();
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001515 bsc_subscr_conn_fsm_init();
1516 handover_fsm_init();
1517
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001518 ho_set_algorithm(bsc_gsmnet->ho, 2);
1519 ho_set_ho_active(bsc_gsmnet->ho, true);
1520 ho_set_hodec2_as_active(bsc_gsmnet->ho, true);
1521 ho_set_hodec2_min_rxlev(bsc_gsmnet->ho, -100);
1522 ho_set_hodec2_rxlev_avg_win(bsc_gsmnet->ho, 1);
1523 ho_set_hodec2_rxlev_neigh_avg_win(bsc_gsmnet->ho, 1);
1524 ho_set_hodec2_rxqual_avg_win(bsc_gsmnet->ho, 10);
1525 ho_set_hodec2_pwr_hysteresis(bsc_gsmnet->ho, 3);
1526 ho_set_hodec2_pwr_interval(bsc_gsmnet->ho, 1);
1527 ho_set_hodec2_afs_bias_rxlev(bsc_gsmnet->ho, 0);
1528 ho_set_hodec2_min_rxqual(bsc_gsmnet->ho, 5);
1529 ho_set_hodec2_afs_bias_rxqual(bsc_gsmnet->ho, 0);
1530 ho_set_hodec2_max_distance(bsc_gsmnet->ho, 9999);
1531 ho_set_hodec2_ho_max(bsc_gsmnet->ho, 9999);
1532 ho_set_hodec2_penalty_max_dist(bsc_gsmnet->ho, 300);
1533 ho_set_hodec2_penalty_failed_ho(bsc_gsmnet->ho, 60);
1534 ho_set_hodec2_penalty_failed_as(bsc_gsmnet->ho, 60);
1535
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +07001536 /* We don't really need any specific model here */
1537 bts_model_unknown_init();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001538
Neels Hofmeyr00727552018-02-21 14:33:15 +01001539 test_case = test_cases[test_case_i];
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001540
1541 fprintf(stderr, "--------------------\n");
1542 fprintf(stderr, "Performing the following test %d (algorithm %s):\n%s",
Neels Hofmeyr00727552018-02-21 14:33:15 +01001543 test_case_i, test_case[0], test_case[1]);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001544 algorithm = atoi(test_case[0]);
1545 test_case += 2;
1546 fprintf(stderr, "--------------------\n");
1547
1548 /* Disable the congestion check timer, we will trigger manually. */
1549 bsc_gsmnet->hodec2.congestion_check_interval_s = 0;
1550
1551 handover_decision_1_init();
1552 hodec2_init(bsc_gsmnet);
1553
1554 while (*test_case) {
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001555 if (!strcmp(*test_case, "create-n-bts")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001556 int n = atoi(test_case[1]);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001557 for (i = 0; i < n; i++)
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001558 create_bts(1, bts_default_ts);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001559 test_case += 2;
1560 } else
Neels Hofmeyrcfbf11f2020-11-12 23:12:48 +01001561 if (!strcmp(*test_case, "create-bts")) {
1562 /* new BTS with one TRX:
1563 * "create-bts", "1", "CCCH+SDCCH4", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H", "TCH/H", "PDCH",
1564 *
1565 * new BTS with two TRX:
1566 * "create-bts", "2", "CCCH+SDCCH4", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H", "TCH/H", "PDCH",
1567 * "SDCCH8", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H", "TCH/H", "PDCH",
1568 */
1569 int num_trx = atoi(test_case[1]);
1570 const char * const * ts_cfg = (void*)&test_case[2];
1571 create_bts(num_trx, ts_cfg);
1572 test_case += 2 + 8 * num_trx;
1573 } else
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001574 if (!strcmp(*test_case, "as-enable")) {
1575 fprintf(stderr, "- Set assignment enable state at "
1576 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001577 ho_set_hodec2_as_active(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001578 test_case += 3;
1579 } else
1580 if (!strcmp(*test_case, "ho-enable")) {
1581 fprintf(stderr, "- Set handover enable state at "
1582 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001583 ho_set_ho_active(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001584 test_case += 3;
1585 } else
1586 if (!strcmp(*test_case, "afs-rxlev-improve")) {
1587 fprintf(stderr, "- Set afs RX level improvement at "
1588 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001589 ho_set_hodec2_afs_bias_rxlev(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001590 test_case += 3;
1591 } else
1592 if (!strcmp(*test_case, "afs-rxqual-improve")) {
1593 fprintf(stderr, "- Set afs RX quality improvement at "
1594 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001595 ho_set_hodec2_afs_bias_rxqual(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001596 test_case += 3;
1597 } else
1598 if (!strcmp(*test_case, "set-min-free")) {
1599 fprintf(stderr, "- Setting minimum required free %s "
1600 "slots at BTS %s to %s\n", test_case[2],
1601 test_case[1], test_case[3]);
1602 if (!strcmp(test_case[2], "TCH/F"))
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001603 ho_set_hodec2_tchf_min_slots(bts_by_num_str(test_case[1])->ho, atoi(test_case[3]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001604 else
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001605 ho_set_hodec2_tchh_min_slots(bts_by_num_str(test_case[1])->ho, atoi(test_case[3]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001606 test_case += 4;
1607 } else
1608 if (!strcmp(*test_case, "set-max-ho")) {
1609 fprintf(stderr, "- Setting maximum parallel handovers "
1610 "at BTS %s to %s\n", test_case[1],
1611 test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001612 ho_set_hodec2_ho_max( bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001613 test_case += 3;
1614 } else
1615 if (!strcmp(*test_case, "set-max-ta")) {
1616 fprintf(stderr, "- Setting maximum timing advance "
1617 "at BTS %s to %s\n", test_case[1],
1618 test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001619 ho_set_hodec2_max_distance(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001620 test_case += 3;
1621 } else
1622 if (!strcmp(*test_case, "create-ms")) {
1623 fprintf(stderr, "- Creating mobile #%d at BTS %s on "
1624 "%s with %s codec\n", lchan_num, test_case[1],
1625 test_case[2], test_case[3]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001626 lchan[lchan_num] = create_lchan(bts_by_num_str(test_case[1]),
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001627 !strcmp(test_case[2], "TCH/F"), test_case[3]);
1628 if (!lchan[lchan_num]) {
1629 printf("Failed to create lchan!\n");
1630 return EXIT_FAILURE;
1631 }
1632 fprintf(stderr, " * New MS is at BTS %d TS %d\n",
1633 lchan[lchan_num]->ts->trx->bts->nr,
1634 lchan[lchan_num]->ts->nr);
1635 lchan_num++;
1636 test_case += 4;
1637 } else
1638 if (!strcmp(*test_case, "set-ta")) {
1639 fprintf(stderr, "- Setting maximum timing advance "
1640 "at MS %s to %s\n", test_case[1],
1641 test_case[2]);
1642 meas_ta_ms = atoi(test_case[2]);
1643 test_case += 3;
1644 } else
1645 if (!strcmp(*test_case, "meas-rep")) {
1646 /* meas-rep <lchan-nr> <rxlev> <rxqual> <nr-of-neighbors> [<cell-idx> <rxlev> [...]] */
1647 int n = atoi(test_case[4]);
1648 struct gsm_lchan *lc = lchan[atoi(test_case[1])];
1649 fprintf(stderr, "- Sending measurement report from "
1650 "mobile #%s (rxlev=%s, rxqual=%s)\n",
1651 test_case[1], test_case[2], test_case[3]);
1652 meas_dl_rxlev = atoi(test_case[2]);
1653 meas_dl_rxqual = atoi(test_case[3]);
1654 meas_num_nc = n;
1655 test_case += 5;
1656 for (i = 0; i < n; i++) {
1657 int nr = atoi(test_case[0]);
1658 /* since our bts is not in the list of neighbor
1659 * cells, we need to shift */
1660 if (nr >= lc->ts->trx->bts->nr)
1661 nr++;
1662 fprintf(stderr, " * Neighbor cell #%s, actual "
1663 "BTS %d (rxlev=%s)\n", test_case[0], nr,
1664 test_case[1]);
1665 meas_bcch_f_nc[i] = atoi(test_case[0]);
1666 /* bts number, not counting our own */
1667 meas_rxlev_nc[i] = atoi(test_case[1]);
1668 meas_bsic_nc[i] = 0x3f;
1669 test_case += 2;
1670 }
1671 got_chan_req = 0;
1672 gen_meas_rep(lc);
1673 } else
1674 if (!strcmp(*test_case, "congestion-check")) {
1675 fprintf(stderr, "- Triggering congestion check\n");
1676 got_chan_req = 0;
1677 if (algorithm == 2)
1678 hodec2_congestion_check(bsc_gsmnet);
1679 test_case += 1;
1680 } else
1681 if (!strcmp(*test_case, "expect-chan")) {
1682 fprintf(stderr, "- Expecting channel request at BTS %s "
1683 "TS %s\n", test_case[1], test_case[2]);
1684 if (!got_chan_req) {
1685 printf("Test failed, because no channel was "
1686 "requested\n");
1687 return EXIT_FAILURE;
1688 }
1689 fprintf(stderr, " * Got channel request at BTS %d "
1690 "TS %d\n", chan_req_lchan->ts->trx->bts->nr,
1691 chan_req_lchan->ts->nr);
1692 if (chan_req_lchan->ts->trx->bts->nr
1693 != atoi(test_case[1])) {
1694 printf("Test failed, because channel was not "
1695 "requested on expected BTS\n");
1696 return EXIT_FAILURE;
1697 }
1698 if (chan_req_lchan->ts->nr != atoi(test_case[2])) {
1699 printf("Test failed, because channel was not "
1700 "requested on expected TS\n");
1701 return EXIT_FAILURE;
1702 }
1703 test_case += 3;
1704 } else
1705 if (!strcmp(*test_case, "expect-no-chan")) {
1706 fprintf(stderr, "- Expecting no channel request\n");
1707 if (got_chan_req) {
1708 fprintf(stderr, " * Got channel request at "
1709 "BTS %d TS %d\n",
1710 chan_req_lchan->ts->trx->bts->nr,
1711 chan_req_lchan->ts->nr);
1712 printf("Test failed, because channel was "
1713 "requested\n");
1714 return EXIT_FAILURE;
1715 }
1716 fprintf(stderr, " * Got no channel request\n");
1717 test_case += 1;
1718 } else
1719 if (!strcmp(*test_case, "expect-ho")) {
1720 fprintf(stderr, "- Expecting handover/assignment "
1721 "request at BTS %s TS %s\n", test_case[1],
1722 test_case[2]);
1723 if (!got_ho_req) {
1724 printf("Test failed, because no handover was "
1725 "requested\n");
1726 return EXIT_FAILURE;
1727 }
1728 fprintf(stderr, " * Got handover/assignment request at "
1729 "BTS %d TS %d\n",
1730 ho_req_lchan->ts->trx->bts->nr,
1731 ho_req_lchan->ts->nr);
1732 if (ho_req_lchan->ts->trx->bts->nr
1733 != atoi(test_case[1])) {
1734 printf("Test failed, because "
1735 "handover/assignment was not commanded "
1736 "at the expected BTS\n");
1737 return EXIT_FAILURE;
1738 }
1739 if (ho_req_lchan->ts->nr != atoi(test_case[2])) {
1740 printf("Test failed, because "
1741 "handover/assignment was not commanded "
1742 "at the expected TS\n");
1743 return EXIT_FAILURE;
1744 }
1745 test_case += 3;
1746 } else
1747 if (!strcmp(*test_case, "ack-chan")) {
1748 fprintf(stderr, "- Acknowledging channel request\n");
1749 if (!got_chan_req) {
1750 printf("Cannot ack channel, because no "
1751 "request\n");
1752 return EXIT_FAILURE;
1753 }
1754 test_case += 1;
1755 got_ho_req = 0;
1756 send_chan_act_ack(chan_req_lchan, 1);
1757 } else
1758 if (!strcmp(*test_case, "ho-complete")) {
1759 fprintf(stderr, "- Acknowledging handover/assignment "
1760 "request\n");
1761 if (!got_chan_req) {
1762 printf("Cannot ack handover/assignment, "
1763 "because no chan request\n");
1764 return EXIT_FAILURE;
1765 }
1766 if (!got_ho_req) {
1767 printf("Cannot ack handover/assignment, "
1768 "because no ho request\n");
1769 return EXIT_FAILURE;
1770 }
1771 test_case += 1;
1772 got_chan_req = 0;
1773 got_ho_req = 0;
1774 /* switch lchan */
1775 for (i = 0; i < lchan_num; i++) {
1776 if (lchan[i] == ho_req_lchan) {
1777 fprintf(stderr, " * MS %d changes from "
1778 "BTS=%d TS=%d to BTS=%d "
1779 "TS=%d\n", i,
1780 lchan[i]->ts->trx->bts->nr,
1781 lchan[i]->ts->nr,
1782 chan_req_lchan->ts->trx->bts->nr,
1783 chan_req_lchan->ts->nr);
1784 lchan[i] = chan_req_lchan;
1785 }
1786 }
1787 send_ho_complete(chan_req_lchan, true);
1788 } else
1789 if (!strcmp(*test_case, "ho-failed")) {
1790 fprintf(stderr, "- Making handover fail\n");
1791 if (!got_chan_req) {
1792 printf("Cannot fail handover, because no chan "
1793 "request\n");
1794 return EXIT_FAILURE;
1795 }
1796 test_case += 1;
1797 got_chan_req = 0;
1798 got_ho_req = 0;
1799 send_ho_complete(ho_req_lchan, false);
1800 } else
1801 if (!strcmp(*test_case, "print")) {
1802 fprintf(stderr, "\n%s\n\n", test_case[1]);
1803 test_case += 2;
1804 } else {
1805 printf("Unknown test command '%s', please fix!\n",
1806 *test_case);
1807 return EXIT_FAILURE;
1808 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001809
1810 {
1811 /* Help the lchan out of releasing states */
1812 struct gsm_bts *bts;
1813 llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
1814 struct gsm_bts_trx *trx;
1815 llist_for_each_entry(trx, &bts->trx_list, list) {
1816 int ts_nr;
1817 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
1818 struct gsm_lchan *lchan;
1819 ts_for_each_lchan(lchan, &trx->ts[ts_nr]) {
1820
1821 if (lchan->fi && lchan->fi->state == LCHAN_ST_WAIT_BEFORE_RF_RELEASE) {
1822 osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_WAIT_RF_RELEASE_ACK, 0, 0);
1823 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RSL_RF_CHAN_REL_ACK, 0);
1824 }
1825 }
1826 }
1827 }
1828 }
1829 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001830 }
1831
1832 for (i = 0; i < lchan_num; i++) {
1833 struct gsm_subscriber_connection *conn = lchan[i]->conn;
1834 lchan[i]->conn = NULL;
1835 conn->lchan = NULL;
Harald Welte3561bd42018-01-28 03:04:16 +01001836 osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REGULAR, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001837 }
1838
1839 fprintf(stderr, "--------------------\n");
1840
1841 printf("Test OK\n");
1842
1843 fprintf(stderr, "--------------------\n");
1844
Neels Hofmeyre3416182018-03-05 05:31:14 +01001845 talloc_free(ctx);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001846 return EXIT_SUCCESS;
1847}
1848
1849void rtp_socket_free() {}
1850void rtp_send_frame() {}
1851void rtp_socket_upstream() {}
1852void rtp_socket_create() {}
1853void rtp_socket_connect() {}
1854void rtp_socket_proxy() {}
1855void trau_mux_unmap() {}
1856void trau_mux_map_lchan() {}
1857void trau_recv_lchan() {}
1858void trau_send_frame() {}
Harald Welte3561bd42018-01-28 03:04:16 +01001859int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
1860int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
Vadim Yanitskiy6a26e2c2020-08-26 18:49:08 +07001861void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, uint8_t dlci, enum gsm0808_cause cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001862void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr) {}
Neels Hofmeyr2001dd62020-09-11 23:35:28 +00001863int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_channel)
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001864{ return 0; }
Neels Hofmeyr86ce1052020-09-18 02:49:32 +02001865int bsc_paging_start(struct bsc_paging_params *params)
1866{ return 0; }
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001867void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) {}
1868void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001869void bsc_cm_update(struct gsm_subscriber_connection *conn,
1870 const uint8_t *cm2, uint8_t cm2_len,
1871 const uint8_t *cm3, uint8_t cm3_len) {}
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001872struct gsm0808_handover_required;
1873int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell_id_list2 *target_cells)
1874{ return 0; }
1875int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, struct msgb *rr_ho_command)
1876{ return 0; }
1877int bsc_tx_bssmap_ho_detect(struct gsm_subscriber_connection *conn) { return 0; }
1878enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn,
1879 struct gsm_lchan *lchan) { return HO_RESULT_OK; }
1880void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001881void osmo_bsc_sigtran_tx_reset(void) {}
Neels Hofmeyre95b92b2020-10-09 17:18:29 +02001882void osmo_bsc_sigtran_tx_reset_ack(void) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001883void osmo_bsc_sigtran_reset(void) {}
1884void bssmap_reset_alloc(void) {}
1885void bssmap_reset_is_conn_ready(void) {}