blob: b469f036bc19934e1ff18c953598deba07dadcd8 [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{
179 enum gsm_phys_chan_config pchan = gsm_pchan_parse(str);
180 if (pchan < 0) {
181 fprintf(stderr, "Invalid timeslot pchan type: %s\n", str);
182 exit(1);
183 }
184 return pchan;
185}
186
187const char * const bts_default_ts[] = {
188 "CCCH+SDCCH4", "TCH/F", "TCH/F", "TCH/F", "TCH/F", "TCH/H", "TCH/H", "NONE",
189};
190
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100191static struct gsm_bts *create_bts(int num_trx, const char * const *ts_args)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100192{
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100193 static int arfcn = 870;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100194 struct gsm_bts *bts;
195 struct e1inp_sign_link *rsl_link;
196 int i;
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100197 int trx_i;
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100198 struct gsm_bts_trx *trx;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100199
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +0700200 bts = bsc_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_UNKNOWN, 0x3f);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100201 if (!bts) {
202 printf("No resource for bts1\n");
203 return NULL;
204 }
205
206 bts->location_area_code = 23;
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100207 bts->c0->arfcn = arfcn++;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100208
209 bts->codec.efr = 1;
210 bts->codec.hr = 1;
211 bts->codec.amr = 1;
212
Neels Hofmeyre3416182018-03-05 05:31:14 +0100213 rsl_link = talloc_zero(ctx, struct e1inp_sign_link);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100214 rsl_link->trx = bts->c0;
215 bts->c0->rsl_link = rsl_link;
216
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100217 for (trx_i = 0; trx_i < num_trx; trx_i++) {
218 while (!(trx = gsm_bts_trx_num(bts, trx_i)))
219 gsm_bts_trx_alloc(bts);
Neels Hofmeyre3eb67c2020-11-12 22:53:59 +0100220
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100221 trx->mo.nm_state.operational = NM_OPSTATE_ENABLED;
222 trx->mo.nm_state.availability = NM_AVSTATE_OK;
223 trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;
224 trx->bb_transc.mo.nm_state.operational = NM_OPSTATE_ENABLED;
225 trx->bb_transc.mo.nm_state.availability = NM_AVSTATE_OK;
226 trx->bb_transc.mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100227
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100228 /* 4 full rate and 4 half rate channels */
229 for (i = 0; i < 8; i++) {
230 trx->ts[i].pchan_from_config = pchan_from_str(ts_args[trx_i * 8 + i]);
231 if (trx->ts[i].pchan_from_config == GSM_PCHAN_NONE)
232 continue;
233 trx->ts[i].mo.nm_state.operational = NM_OPSTATE_ENABLED;
234 trx->ts[i].mo.nm_state.availability = NM_AVSTATE_OK;
235 trx->ts[i].mo.nm_state.administrative = NM_STATE_UNLOCKED;
236 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200237
Neels Hofmeyrdd7b7102020-11-12 22:54:58 +0100238 for (i = 0; i < ARRAY_SIZE(bts->c0->ts); i++) {
239 /* make sure ts->lchans[] get initialized */
240 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_RSL_READY, 0);
241 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_OML_READY, 0);
242 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100243 }
Neels Hofmeyr780f0282020-11-12 22:51:58 +0100244
245 for (i = 0; i < bsc_gsmnet->num_bts; i++) {
246 if (gsm_generate_si(gsm_bts_num(bsc_gsmnet, i), SYSINFO_TYPE_2) <= 0)
247 fprintf(stderr, "Error generating SI2\n");
248 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100249 return bts;
250}
251
252void create_conn(struct gsm_lchan *lchan)
253{
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200254 static unsigned int next_imsi = 0;
255 char imsi[sizeof(lchan->conn->bsub->imsi)];
256 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Welte3561bd42018-01-28 03:04:16 +0100257 struct gsm_subscriber_connection *conn;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200258 struct mgcp_client *fake_mgcp_client = (void*)talloc_zero(net, int);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200259
260 conn = bsc_subscr_con_allocate(net);
Harald Welte3561bd42018-01-28 03:04:16 +0100261
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200262 conn->user_plane.mgw_endpoint = osmo_mgcpc_ep_alloc(conn->fi,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200263 GSCON_EV_FORGET_MGW_ENDPOINT,
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200264 fake_mgcp_client,
265 net->mgw.tdefs,
266 "test",
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200267 "fake endpoint");
Alexander Chemeris69ba8be2020-05-10 22:48:01 +0300268 conn->sccp.msc = osmo_msc_data_alloc(net, 0);
Harald Welte3561bd42018-01-28 03:04:16 +0100269
270 lchan->conn = conn;
271 conn->lchan = lchan;
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200272
273 /* Make up a new IMSI for this test, for logging the subscriber */
274 next_imsi ++;
275 snprintf(imsi, sizeof(imsi), "%06u", next_imsi);
Neels Hofmeyr86a1dca2020-09-15 01:03:58 +0000276 lchan->conn->bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers, imsi, BSUB_USE_CONN);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200277
Harald Welte3561bd42018-01-28 03:04:16 +0100278 /* kick the FSM from INIT through to the ACTIVE state */
Neels Hofmeyrd1e7d392020-09-27 23:34:57 +0200279 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MO_COMPL_L3, NULL);
Harald Welte3561bd42018-01-28 03:04:16 +0100280 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100281}
282
283/* create lchan */
284struct gsm_lchan *create_lchan(struct gsm_bts *bts, int full_rate, char *codec)
285{
286 struct gsm_lchan *lchan;
287
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200288 lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100289 if (!lchan) {
290 printf("No resource for lchan\n");
291 exit(EXIT_FAILURE);
292 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200293
294 /* serious hack into osmo_fsm */
295 lchan->fi->state = LCHAN_ST_ESTABLISHED;
296 lchan->ts->fi->state = TS_ST_IN_USE;
297 LOG_LCHAN(lchan, LOGL_DEBUG, "activated by handover_test.c\n");
298
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100299 create_conn(lchan);
300 if (!strcasecmp(codec, "FR") && full_rate)
301 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
302 else if (!strcasecmp(codec, "HR") && !full_rate)
303 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
304 else if (!strcasecmp(codec, "EFR") && full_rate)
305 lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100306 else if (!strcasecmp(codec, "AMR")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100307 lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100308 lchan->activate.info.s15_s0 = 0x0002;
309 } else {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100310 printf("Given codec unknown\n");
311 exit(EXIT_FAILURE);
312 }
313
314 lchan->conn->codec_list = (struct gsm0808_speech_codec_list){
315 .codec = {
316 { .fi=true, .type=GSM0808_SCT_FR1, },
317 { .fi=true, .type=GSM0808_SCT_FR2, },
318 { .fi=true, .type=GSM0808_SCT_FR3, },
319 { .fi=true, .type=GSM0808_SCT_HR1, },
320 { .fi=true, .type=GSM0808_SCT_HR3, },
321 },
322 .len = 5,
323 };
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100324
325 return lchan;
326}
327
328/* parse channel request */
329
330static int got_chan_req = 0;
331static struct gsm_lchan *chan_req_lchan = NULL;
332
333static int parse_chan_act(struct gsm_lchan *lchan, uint8_t *data)
334{
335 chan_req_lchan = lchan;
336 return 0;
337}
338
339static int parse_chan_rel(struct gsm_lchan *lchan, uint8_t *data)
340{
341 chan_req_lchan = lchan;
342 return 0;
343}
344
345/* parse handover request */
346
347static int got_ho_req = 0;
348static struct gsm_lchan *ho_req_lchan = NULL;
349
350static int parse_ho_command(struct gsm_lchan *lchan, uint8_t *data, int len)
351{
352 struct gsm48_hdr *gh = (struct gsm48_hdr *) data;
353 struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) gh->data;
354 int arfcn;
355 struct gsm_bts *neigh;
356
357 switch (gh->msg_type) {
358 case GSM48_MT_RR_HANDO_CMD:
359 arfcn = (ho->cell_desc.arfcn_hi << 8) | ho->cell_desc.arfcn_lo;
360
361 /* look up trx. since every dummy bts uses different arfcn and
362 * only one trx, it is simple */
363 llist_for_each_entry(neigh, &bsc_gsmnet->bts_list, list) {
364 if (neigh->c0->arfcn != arfcn)
365 continue;
366 ho_req_lchan = lchan;
367 return 0;
368 }
369 break;
370 case GSM48_MT_RR_ASS_CMD:
371 ho_req_lchan = lchan;
372 return 0;
373 break;
374 default:
375 fprintf(stderr, "Error, expecting HO or AS command\n");
376 return -EINVAL;
377 }
378
379 return -1;
380}
381
382/* send channel activation ack */
383static void send_chan_act_ack(struct gsm_lchan *lchan, int act)
384{
385 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
386 struct abis_rsl_dchan_hdr *dh;
387
388 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
389 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
390 dh->c.msg_type = (act) ? RSL_MT_CHAN_ACTIV_ACK : RSL_MT_RF_CHAN_REL_ACK;
391 dh->ie_chan = RSL_IE_CHAN_NR;
392 dh->chan_nr = gsm_lchan2chan_nr(lchan);
393
394 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
395 msg->l2h = (unsigned char *)dh;
396
397 abis_rsl_rcvmsg(msg);
398}
399
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200400/* Send RLL Est Ind for SAPI[0] */
401static void send_est_ind(struct gsm_lchan *lchan)
402{
403 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
404 struct abis_rsl_rll_hdr *rh;
405 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
406
407 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
408 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
409 rh->c.msg_type = RSL_MT_EST_IND;
410 rh->ie_chan = RSL_IE_CHAN_NR;
411 rh->chan_nr = chan_nr;
412 rh->ie_link_id = RSL_IE_LINK_IDENT;
413 rh->link_id = 0x00;
414
415 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
416 msg->l2h = (unsigned char *)rh;
417
418 abis_rsl_rcvmsg(msg);
419}
420
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100421/* send handover complete */
422static void send_ho_complete(struct gsm_lchan *lchan, bool success)
423{
424 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
425 struct abis_rsl_rll_hdr *rh;
426 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
427 uint8_t *buf;
428 struct gsm48_hdr *gh;
429 struct gsm48_ho_cpl *hc;
430
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200431 send_est_ind(lchan);
Neels Hofmeyrac85b342018-07-12 21:23:26 +0200432 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RTP_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200433
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100434 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
435 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
436 rh->c.msg_type = RSL_MT_DATA_IND;
437 rh->ie_chan = RSL_IE_CHAN_NR;
438 rh->chan_nr = chan_nr;
439 rh->ie_link_id = RSL_IE_LINK_IDENT;
440 rh->link_id = 0x00;
441
442 buf = msgb_put(msg, 3);
443 buf[0] = RSL_IE_L3_INFO;
444 buf[1] = (sizeof(*gh) + sizeof(*hc)) >> 8;
445 buf[2] = (sizeof(*gh) + sizeof(*hc)) & 0xff;
446
447 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
448 hc = (struct gsm48_ho_cpl *) msgb_put(msg, sizeof(*hc));
449
450 gh->proto_discr = GSM48_PDISC_RR;
451 gh->msg_type =
452 success ? GSM48_MT_RR_HANDO_COMPL : GSM48_MT_RR_HANDO_FAIL;
453
454 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
455 msg->l2h = (unsigned char *)rh;
456 msg->l3h = (unsigned char *)gh;
457
458 abis_rsl_rcvmsg(msg);
459}
460
Neels Hofmeyr1d7473c2018-03-05 21:53:18 +0100461/* override, requires '-Wl,--wrap=abis_rsl_sendmsg'.
462 * Catch RSL messages sent towards the BTS. */
463int __real_abis_rsl_sendmsg(struct msgb *msg);
464int __wrap_abis_rsl_sendmsg(struct msgb *msg)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100465{
466 struct abis_rsl_dchan_hdr *dh = (struct abis_rsl_dchan_hdr *) msg->data;
467 struct e1inp_sign_link *sign_link = msg->dst;
468 int rc;
469 struct gsm_lchan *lchan = rsl_lchan_lookup(sign_link->trx, dh->chan_nr, &rc);
470
471 if (rc) {
472 printf("rsl_lchan_lookup() failed\n");
473 exit(1);
474 }
475
476 switch (dh->c.msg_type) {
477 case RSL_MT_CHAN_ACTIV:
478 rc = parse_chan_act(lchan, dh->data);
479 if (rc == 0)
480 got_chan_req = 1;
481 break;
482 case RSL_MT_RF_CHAN_REL:
483 rc = parse_chan_rel(lchan, dh->data);
484 if (rc == 0)
485 send_chan_act_ack(chan_req_lchan, 0);
486 break;
487 case RSL_MT_DATA_REQ:
488 rc = parse_ho_command(lchan, msg->l3h, msgb_l3len(msg));
489 if (rc == 0)
490 got_ho_req = 1;
491 break;
492 case RSL_MT_IPAC_CRCX:
493 break;
Neels Hofmeyr5b1a7d12018-11-06 22:24:07 +0100494 case RSL_MT_DEACTIVATE_SACCH:
495 break;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100496 default:
497 printf("unknown rsl message=0x%x\n", dh->c.msg_type);
498 }
499 return 0;
500}
501
502/* test cases */
503
504static char *test_case_0[] = {
505 "2",
506
507 "Stay in better cell\n\n"
508 "There are many neighbor cells, but only the current cell is the best\n"
509 "cell, so no handover is performed\n",
510
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100511 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100512 "create-ms", "0", "TCH/F", "AMR",
513 "meas-rep", "0", "30","0",
514 "6","0","20","1","21","2","18","3","20","4","23","5","19",
515 "expect-no-chan",
516 NULL
517};
518
519static char *test_case_1[] = {
520 "2",
521
522 "Handover to best better cell\n\n"
523 "The best neighbor cell is selected\n",
524
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100525 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100526 "create-ms", "0", "TCH/F", "AMR",
527 "meas-rep", "0", "10","0",
528 "6","0","20","1","21","2","18","3","20","4","23","5","19",
529 "expect-chan", "5", "1",
530 "ack-chan",
531 "expect-ho", "0", "1",
532 "ho-complete",
533 NULL
534};
535
536static char *test_case_2[] = {
537 "2",
538
539 "Handover and Assignment must be enabled\n\n"
540 "This test will start with disabled assignment and handover. A\n"
541 "better neighbor cell (assignment enabled) will not be selected and \n"
542 "also no assignment from TCH/H to TCH/F to improve quality. There\n"
543 "will be no handover nor assignment. After enabling assignment on the\n"
544 "current cell, the MS will assign to TCH/F. After enabling handover\n"
545 "in the current cell, but disabling in the neighbor cell, handover\n"
546 "will not be performed, until it is enabled in the neighbor cell too.\n",
547
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100548 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100549 "afs-rxlev-improve", "0", "5",
550 "create-ms", "0", "TCH/H", "AMR",
551 "as-enable", "0", "0",
552 "ho-enable", "0", "0",
553 "meas-rep", "0", "0","0", "1","0","30",
554 "expect-no-chan",
555 "as-enable", "0", "1",
556 "meas-rep", "0", "0","0", "1","0","30",
557 "expect-chan", "0", "1",
558 "ack-chan",
559 "expect-ho", "0", "5",
560 "ho-complete",
561 "ho-enable", "0", "1",
562 "ho-enable", "1", "0",
563 "meas-rep", "0", "0","0", "1","0","30",
564 "expect-no-chan",
565 "ho-enable", "1", "1",
566 "meas-rep", "0", "0","0", "1","0","30",
567 "expect-chan", "1", "1",
568 "ack-chan",
569 "expect-ho", "0", "1",
570 "ho-complete",
571 NULL
572};
573
574static char *test_case_3[] = {
575 "2",
576
577 "Penalty timer must not run\n\n"
578 "The MS will try to handover to a better cell, but this will fail.\n"
579 "Even though the cell is still better, handover will not be performed\n"
580 "due to penalty timer after handover failure\n",
581
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100582 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100583 "create-ms", "0", "TCH/F", "AMR",
584 "meas-rep", "0", "20","0", "1","0","30",
585 "expect-chan", "1", "1",
586 "ack-chan",
587 "expect-ho", "0", "1",
588 "ho-failed",
589 "meas-rep", "0", "20","0", "1","0","30",
590 "expect-no-chan",
591 NULL
592};
593
594static char *test_case_4[] = {
595 "2",
596
597 "TCH/H keeping with HR codec\n\n"
598 "The MS is using half rate V1 codec, but the better cell is congested\n"
599 "at TCH/H slots. As the congestion is removed, the handover takes\n"
600 "place.\n",
601
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100602 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100603 "set-min-free", "1", "TCH/H", "4",
604 "create-ms", "0", "TCH/H", "HR",
605 "meas-rep", "0", "20","0", "1","0","30",
606 "expect-no-chan",
607 "set-min-free", "1", "TCH/H", "3",
608 "meas-rep", "0", "20","0", "1","0","30",
609 "expect-chan", "1", "5",
610 "ack-chan",
611 "expect-ho", "0", "5",
612 "ho-complete",
613 NULL
614};
615
616static char *test_case_5[] = {
617 "2",
618
619 "TCH/F keeping with FR codec\n\n"
620 "The MS is using full rate V1 codec, but the better cell is congested\n"
621 "at TCH/F slots. As the congestion is removed, the handover takes\n"
622 "place.\n",
623
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100624 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100625 "set-min-free", "1", "TCH/F", "4",
626 "create-ms", "0", "TCH/F", "FR",
627 "meas-rep", "0", "20","0", "1","0","30",
628 "expect-no-chan",
629 "set-min-free", "1", "TCH/F", "3",
630 "meas-rep", "0", "20","0", "1","0","30",
631 "expect-chan", "1", "1",
632 "ack-chan",
633 "expect-ho", "0", "1",
634 "ho-complete",
635 NULL
636};
637
638static char *test_case_6[] = {
639 "2",
640
641 "TCH/F keeping with EFR codec\n\n"
642 "The MS is using full rate V2 codec, but the better cell is congested\n"
643 "at TCH/F slots. As the congestion is removed, the handover takes\n"
644 "place.\n",
645
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100646 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100647 "set-min-free", "1", "TCH/F", "4",
648 "create-ms", "0", "TCH/F", "EFR",
649 "meas-rep", "0", "20","0", "1","0","30",
650 "expect-no-chan",
651 "set-min-free", "1", "TCH/F", "3",
652 "meas-rep", "0", "20","0", "1","0","30",
653 "expect-chan", "1", "1",
654 "ack-chan",
655 "expect-ho", "0", "1",
656 "ho-complete",
657 NULL
658};
659
660static char *test_case_7[] = {
661 "2",
662
663 "TCH/F to TCH/H changing with AMR codec\n\n"
664 "The MS is using AMR V3 codec, the better cell is congested at TCH/F\n"
665 "slots. The handover is performed to non-congested TCH/H slots.\n",
666
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100667 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100668 "set-min-free", "1", "TCH/F", "4",
669 "create-ms", "0", "TCH/F", "AMR",
670 "meas-rep", "0", "20","0", "1","0","30",
671 "expect-chan", "1", "5",
672 "ack-chan",
673 "expect-ho", "0", "1",
674 "ho-complete",
675 NULL
676};
677
678static char *test_case_8[] = {
679 "2",
680
681 "No handover to a cell with no slots available\n\n"
682 "If no slot is available, no handover is performed\n",
683
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100684 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100685 "create-ms", "0", "TCH/F", "AMR",
686 "create-ms", "1", "TCH/F", "AMR",
687 "create-ms", "1", "TCH/F", "AMR",
688 "create-ms", "1", "TCH/F", "AMR",
689 "create-ms", "1", "TCH/F", "AMR",
690 "create-ms", "1", "TCH/H", "AMR",
691 "create-ms", "1", "TCH/H", "AMR",
692 "create-ms", "1", "TCH/H", "AMR",
693 "create-ms", "1", "TCH/H", "AMR",
694 "meas-rep", "0", "0","0", "1","0","30",
695 "expect-no-chan",
696 NULL
697};
698
699static char *test_case_9[] = {
700 "2",
701
702 "No more parallel handovers, if max_unsync_ho is defined\n\n"
703 "There are tree mobiles that want to handover, but only two can do\n"
704 "it at a time, because the maximum number is limited to two.\n",
705
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100706 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100707 "set-max-ho", "1", "2",
708 "create-ms", "0", "TCH/F", "AMR",
709 "create-ms", "0", "TCH/F", "AMR",
710 "create-ms", "0", "TCH/F", "AMR",
711 "meas-rep", "0", "0","0", "1","0","30",
712 "expect-chan", "1", "1",
713 "meas-rep", "1", "0","0", "1","0","30",
714 "expect-chan", "1", "2",
715 "meas-rep", "2", "0","0", "1","0","30",
716 "expect-no-chan",
717 NULL
718};
719
720static char *test_case_10[] = {
721 "2",
722
723 "Hysteresis\n\n"
724 "If neighbor cell is better, handover is only performed if the\n"
Martin Haukea29affd2019-11-13 22:10:41 +0100725 "amount of improvement is greater or equal hyteresis\n",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100726
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100727 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100728 "create-ms", "0", "TCH/F", "AMR",
729 "meas-rep", "0", "27","0", "1","0","30",
730 "expect-no-chan",
731 "meas-rep", "0", "26","0", "1","0","30",
732 "expect-chan", "1", "1",
733 "ack-chan",
734 "expect-ho", "0", "1",
735 "ho-complete",
736 NULL
737};
738
739static char *test_case_11[] = {
740 "2",
741
742 "No Hysteresis and minimum RX level\n\n"
743 "If current cell's RX level is below mimium level, handover must be\n"
744 "performed, no matter of the hysteresis. First do not perform\n"
745 "handover to better neighbor cell, because the hysteresis is not\n"
746 "met. Second do not perform handover because better neighbor cell is\n"
747 "below minimum RX level. Third perform handover because current cell\n"
748 "is below minimum RX level, even if the better neighbor cell (minimum\n"
749 "RX level reached) does not meet the hysteresis.\n",
750
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", "10","0", "1","0","11",
754 "expect-no-chan",
755 "meas-rep", "0", "8","0", "1","0","9",
756 "expect-no-chan",
757 "meas-rep", "0", "9","0", "1","0","10",
758 "expect-chan", "1", "1",
759 "ack-chan",
760 "expect-ho", "0", "1",
761 "ho-complete",
762 NULL
763};
764
765static char *test_case_12[] = {
766 "2",
767
768 "No handover to congested cell\n\n"
769 "The better neighbor cell is congested, so no handover is performed.\n"
770 "After the congestion is over, handover will be performed.\n",
771
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100772 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100773 "create-ms", "0", "TCH/F", "AMR",
774 "set-min-free", "1", "TCH/F", "4",
775 "set-min-free", "1", "TCH/H", "4",
776 "meas-rep", "0", "20","0", "1","0","30",
777 "expect-no-chan",
778 "set-min-free", "1", "TCH/F", "3",
779 "set-min-free", "1", "TCH/H", "3",
780 "meas-rep", "0", "20","0", "1","0","30",
781 "expect-chan", "1", "1",
782 "ack-chan",
783 "expect-ho", "0", "1",
784 "ho-complete",
785 NULL
786};
787
788static char *test_case_13[] = {
789 "2",
790
791 "Handover to balance congestion\n\n"
792 "The current and the better cell are congested, so no handover is\n"
793 "performed. This is because handover would congest the neighbor cell\n"
794 "more. After congestion raises in the current cell, the handover is\n"
795 "performed to balance congestion\n",
796
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100797 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100798 "create-ms", "0", "TCH/F", "AMR",
799 "set-min-free", "0", "TCH/F", "4",
800 "set-min-free", "0", "TCH/H", "4",
801 "set-min-free", "1", "TCH/F", "4",
802 "set-min-free", "1", "TCH/H", "4",
803 "meas-rep", "0", "20","0", "1","0","30",
804 "expect-no-chan",
805 "create-ms", "0", "TCH/F", "AMR",
806 "meas-rep", "0", "20","0", "1","0","30",
807 "expect-chan", "1", "1",
808 "ack-chan",
809 "expect-ho", "0", "1",
810 "ho-complete",
811 NULL
812};
813
814static char *test_case_14[] = {
815 "2",
816
817 "Handover to congested cell, if RX level is below minimum\n\n"
818 "The better neighbor cell is congested, so no handover is performed.\n"
819 "If the RX level of the current cell drops below minimum acceptable\n"
820 "level, the handover is performed.\n",
821
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100822 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100823 "create-ms", "0", "TCH/F", "AMR",
824 "set-min-free", "1", "TCH/F", "4",
825 "set-min-free", "1", "TCH/H", "4",
826 "meas-rep", "0", "10","0", "1","0","30",
827 "expect-no-chan",
828 "meas-rep", "0", "9","0", "1","0","30",
829 "expect-chan", "1", "1",
830 "ack-chan",
831 "expect-ho", "0", "1",
832 "ho-complete",
833 NULL
834};
835
836static char *test_case_15[] = {
837 "2",
838
839 "Handover to cell with worse RXLEV, if RXQUAL is below minimum\n\n"
840 "The neighbor cell has worse RXLEV, so no handover is performed.\n"
841 "If the RXQUAL of the current cell drops below minimum acceptable\n"
842 "level, the handover is performed. It is also required that 10\n"
843 "reports are received, before RXQUAL is checked.\n",
844 /* (See also test 28, which tests for RXQUAL triggering HO to congested cell.) */
845 /* TODO: bad RXQUAL may want to prefer assignment within the same cell to avoid interference.
Martin Haukea29affd2019-11-13 22:10:41 +0100846 * See Performance Enhancements in a Frequency Hopping GSM Network (Nielsen Wigard 2002), Chapter
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100847 * 2.1.1, "Interference" in the list of triggers on p.157. */
848
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100849 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100850 "create-ms", "0", "TCH/F", "AMR",
851 "meas-rep", "0", "40","6", "1","0","30",
852 "expect-no-chan",
853 "meas-rep", "0", "40","6", "1","0","30",
854 "expect-no-chan",
855 "meas-rep", "0", "40","6", "1","0","30",
856 "expect-no-chan",
857 "meas-rep", "0", "40","6", "1","0","30",
858 "expect-no-chan",
859 "meas-rep", "0", "40","6", "1","0","30",
860 "expect-no-chan",
861 "meas-rep", "0", "40","6", "1","0","30",
862 "expect-no-chan",
863 "meas-rep", "0", "40","6", "1","0","30",
864 "expect-no-chan",
865 "meas-rep", "0", "40","6", "1","0","30",
866 "expect-no-chan",
867 "meas-rep", "0", "40","6", "1","0","30",
868 "expect-no-chan",
869 "meas-rep", "0", "40","6", "1","0","30",
870 "expect-chan", "1", "1",
871 "ack-chan",
872 "expect-ho", "0", "1",
873 "ho-complete",
874 NULL
875};
876
877static char *test_case_16[] = {
878 "2",
879
880 "Handover due to maximum TA exceeded\n\n"
881 "The MS in the current (best) cell has reached maximum allowed timing\n"
882 "advance. No handover is performed until the timing advance exceeds\n"
883 "it. The originating cell is still the best, but no handover is\n"
884 "performed back to that cell, because the penalty timer (due to\n"
885 "maximum allowed timing advance) is running.\n",
886
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100887 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100888 "create-ms", "0", "TCH/F", "AMR",
889 "set-max-ta", "0", "5", /* of cell */
890 "set-ta", "0", "5", /* of ms */
891 "meas-rep", "0", "30","0", "1","0","20",
892 "expect-no-chan",
893 "set-ta", "0", "6", /* of ms */
894 "meas-rep", "0", "30","0", "1","0","20",
895 "expect-chan", "1", "1",
896 "ack-chan",
897 "expect-ho", "0", "1",
898 "ho-complete",
899 "meas-rep", "0", "20","0", "1","0","30",
900 "expect-no-chan",
901 NULL
902};
903
904static char *test_case_17[] = {
905 "2",
906
907 "Congestion check: No congestion\n\n"
908 "Three cells have different number of used slots, but there is no\n"
909 "congestion in any of these cells. No handover is performed.\n",
910
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100911 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100912 "set-min-free", "0", "TCH/F", "2",
913 "set-min-free", "0", "TCH/H", "2",
914 "set-min-free", "1", "TCH/F", "2",
915 "set-min-free", "1", "TCH/H", "2",
916 "set-min-free", "2", "TCH/F", "2",
917 "set-min-free", "2", "TCH/H", "2",
918 "create-ms", "0", "TCH/F", "AMR",
919 "create-ms", "0", "TCH/F", "AMR",
920 "create-ms", "0", "TCH/H", "AMR",
921 "create-ms", "0", "TCH/H", "AMR",
922 "create-ms", "1", "TCH/F", "AMR",
923 "create-ms", "1", "TCH/H", "AMR",
924 "meas-rep", "0", "30","0", "2","0","20","1","20",
925 "expect-no-chan",
926 "meas-rep", "1", "30","0", "2","0","20","1","20",
927 "expect-no-chan",
928 "meas-rep", "2", "30","0", "2","0","20","1","20",
929 "expect-no-chan",
930 "meas-rep", "3", "30","0", "2","0","20","1","20",
931 "expect-no-chan",
932 "meas-rep", "4", "30","0", "2","0","20","1","20",
933 "expect-no-chan",
934 "meas-rep", "5", "30","0", "2","0","20","1","20",
935 "expect-no-chan",
936 "congestion-check",
937 "expect-no-chan",
938 NULL
939};
940
941static char *test_case_18[] = {
942 "2",
943
944 "Congestion check: One out of three cells is congested\n\n"
945 "Three cells have different number of used slots, but there is\n"
946 "congestion at TCH/F in the first cell. Handover is performed with\n"
947 "the best candidate.\n",
948
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100949 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100950 "set-min-free", "0", "TCH/F", "2",
951 "set-min-free", "0", "TCH/H", "2",
952 "set-min-free", "1", "TCH/F", "2",
953 "set-min-free", "1", "TCH/H", "2",
954 "set-min-free", "2", "TCH/F", "2",
955 "set-min-free", "2", "TCH/H", "2",
956 "create-ms", "0", "TCH/F", "AMR",
957 "create-ms", "0", "TCH/F", "AMR",
958 "create-ms", "0", "TCH/F", "AMR",
959 "create-ms", "0", "TCH/H", "AMR",
960 "create-ms", "0", "TCH/H", "AMR",
961 "create-ms", "1", "TCH/F", "AMR",
962 "create-ms", "1", "TCH/H", "AMR",
963 "meas-rep", "0", "30","0", "2","0","20","1","20",
964 "expect-no-chan",
965 "meas-rep", "1", "30","0", "2","0","20","1","20",
966 "expect-no-chan",
967 "meas-rep", "2", "30","0", "2","0","21","1","20",
968 "expect-no-chan",
969 "meas-rep", "3", "30","0", "2","0","20","1","20",
970 "expect-no-chan",
971 "meas-rep", "4", "30","0", "2","0","20","1","20",
972 "expect-no-chan",
973 "meas-rep", "5", "30","0", "2","0","20","1","20",
974 "expect-no-chan",
975 "meas-rep", "6", "30","0", "2","0","20","1","20",
976 "expect-no-chan",
977 "congestion-check",
978 "expect-chan", "1", "2",
979 "ack-chan",
Neels Hofmeyr72d64e72020-11-16 18:07:31 +0100980 "expect-ho", "0", "3", /* best candidate is MS 2 at BTS 0, TS 3 */
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100981 "ho-complete",
982 NULL
983};
984
985static char *test_case_19[] = {
986 "2",
987
988 "Congestion check: Balancing over congested cells\n\n"
Neels Hofmeyr1336d942020-08-10 21:13:55 +0200989 "Two cells are congested, but the second cell is less congested.\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100990 "Handover is performed to solve the congestion.\n",
991
Neels Hofmeyr4942da82020-11-12 22:58:17 +0100992 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100993 "set-min-free", "0", "TCH/F", "4",
994 "set-min-free", "1", "TCH/F", "4",
995 "create-ms", "0", "TCH/F", "FR",
996 "create-ms", "0", "TCH/F", "FR",
997 "create-ms", "0", "TCH/F", "FR",
998 "create-ms", "1", "TCH/F", "FR",
999 "meas-rep", "0", "30","0", "1","0","20",
1000 "expect-no-chan",
1001 "meas-rep", "1", "30","0", "1","0","21",
1002 "expect-no-chan",
1003 "meas-rep", "2", "30","0", "1","0","20",
1004 "expect-no-chan",
1005 "meas-rep", "3", "30","0", "1","0","20",
1006 "expect-no-chan",
1007 "congestion-check",
1008 "expect-chan", "1", "2",
1009 "ack-chan",
1010 "expect-ho", "0", "2", /* best candidate is MS 1 at BTS 0, TS 2 */
1011 "ho-complete",
1012 NULL
1013};
1014
1015static char *test_case_20[] = {
1016 "2",
1017
1018 "Congestion check: Solving congestion by handover TCH/F -> TCH/H\n\n"
1019 "Two BTS, one MS in the first congested BTS must handover to\n"
1020 "non-congested TCH/H of second BTS, in order to solve congestion\n",
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001021 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001022 "set-min-free", "0", "TCH/F", "4",
1023 "set-min-free", "0", "TCH/H", "4",
1024 "set-min-free", "1", "TCH/F", "4",
1025 "create-ms", "0", "TCH/F", "AMR",
1026 "meas-rep", "0", "30","0", "1","0","30",
1027 "expect-no-chan",
1028 "congestion-check",
1029 "expect-chan", "1", "5",
1030 "ack-chan",
1031 "expect-ho", "0", "1",
1032 "ho-complete",
1033 NULL
1034};
1035
1036static char *test_case_21[] = {
1037 "2",
1038
1039 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1040 "Two BTS, one MS in the first congested BTS must handover to\n"
1041 "less-congested TCH/H of second BTS, in order to balance congestion\n",
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001042 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001043 "set-min-free", "0", "TCH/F", "4",
1044 "set-min-free", "0", "TCH/H", "4",
1045 "set-min-free", "1", "TCH/F", "4",
1046 "set-min-free", "1", "TCH/H", "4",
1047 "create-ms", "0", "TCH/F", "AMR",
1048 "create-ms", "0", "TCH/F", "AMR",
1049 "create-ms", "0", "TCH/H", "AMR",
1050 "meas-rep", "0", "30","0", "1","0","30",
1051 "expect-no-chan",
1052 "congestion-check",
1053 "expect-chan", "1", "1",
1054 "ack-chan",
1055 "expect-ho", "0", "1",
1056 "ho-complete",
1057 NULL
1058};
1059
1060static char *test_case_22[] = {
1061 "2",
1062
1063 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1064 "There is only one BTS. The TCH/H slots are congested. Since\n"
1065 "assignment is performed to less-congested TCH/F, the candidate with\n"
1066 "the worst RX level is chosen.\n",
1067
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001068 "create-n-bts", "1",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001069 "set-min-free", "0", "TCH/F", "4",
1070 "set-min-free", "0", "TCH/H", "4",
1071 "create-ms", "0", "TCH/H", "AMR",
1072 "create-ms", "0", "TCH/H", "AMR",
1073 "create-ms", "0", "TCH/H", "AMR",
1074 "meas-rep", "0", "30","0", "0",
1075 "meas-rep", "1", "34","0", "0",
1076 "meas-rep", "2", "20","0", "0",
1077 "expect-no-chan",
1078 "congestion-check",
1079 "expect-chan", "0", "1",
1080 "ack-chan",
1081 "expect-ho", "0", "6",
1082 "ho-complete",
1083 NULL
1084};
1085
1086static char *test_case_23[] = {
1087 "2",
1088
1089 "Story: 'A neighbor is your friend'\n",
1090
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001091 "create-n-bts", "3",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001092
1093 "print",
1094 "Andreas is driving along the coast, on a sunny june afternoon.\n"
1095 "Suddenly he is getting a call from his friend and neighbor Axel.\n"
1096 "\n"
1097 "What happens: Two MS are created, #0 for Axel, #1 for Andreas.",
1098 /* Axel */
1099 "create-ms", "2", "TCH/F", "AMR",
1100 /* andreas */
1101 "create-ms", "0", "TCH/F", "AMR",
1102 "meas-rep", "1", "40","0", "1","0","30",
1103 "expect-no-chan",
1104
1105 "print",
1106 "Axel asks Andreas if he would like to join them for a barbecue.\n"
1107 "Axel's house is right in the neighborhood and the weather is fine.\n"
1108 "Andreas agrees, so he drives to a close store to buy some barbecue\n"
1109 "skewers.\n"
1110 "\n"
1111 "What happens: While driving, a different cell (mounted atop the\n"
1112 "store) becomes better.",
1113 /* drive to bts 1 */
1114 "meas-rep", "1", "20","0", "1","0","35",
1115 "expect-chan", "1", "1",
1116 "ack-chan",
1117 "expect-ho", "0", "1",
1118 "ho-complete",
1119
1120 "print",
1121 "While Andreas is walking into the store, Axel asks, if he could also\n"
1122 "bring some beer. Andreas has problems understanding him: \"I have a\n"
1123 "bad reception here. The cell tower is right atop the store, but poor\n"
1124 "coverage inside. Can you repeat please?\"\n"
1125 "\n"
1126 "What happens: Inside the store the close cell is so bad, that\n"
1127 "handover back to the previous cell is required.",
1128 /* bts 1 becomes bad, so bts 0 helps out */
1129 "meas-rep", "1", "5","0", "1","0","20",
1130 "expect-chan", "0", "1",
1131 "ack-chan",
1132 "expect-ho", "1", "1",
1133 "ho-complete",
1134
1135 "print",
1136 "After Andreas bought skewers and beer, he leaves the store.\n"
1137 "\n"
1138 "What happens: Outside the store the close cell is better again, so\n"
1139 "handover back to the that cell is performed.",
1140 /* bts 1 becomes better again */
1141 "meas-rep", "1", "20","0", "1","0","35",
1142 "expect-chan", "1", "1",
1143 "ack-chan",
1144 "expect-ho", "0", "1",
1145 "ho-complete",
1146
1147 "print",
1148 /* bts 2 becomes better */
1149 "Andreas drives down to the lake where Axel's house is.\n"
1150 "\n"
1151 "What happens: There is a small cell at Axel's house, which becomes\n"
1152 "better, because the current cell has no good comverage at the lake.",
1153 "meas-rep", "1", "14","0", "2","0","2","1","63",
1154 "expect-chan", "2", "2",
1155 "ack-chan",
1156 "expect-ho", "1", "1",
1157 "ho-complete",
1158
1159 "print",
1160 "Andreas wonders why he still has good radio coverage: \"Last time it\n"
1161 "was so bad\". Axel says: \"I installed a pico cell in my house,\n"
1162 "now we can use our mobile phones down here at the lake.\"",
1163
1164 NULL
1165};
1166
1167static char *test_case_24[] = {
1168 "2",
1169 "No (or not enough) measurements for handover\n\n"
1170 "Do not solve congestion in cell, because there is no measurement.\n"
Martin Haukea29affd2019-11-13 22:10:41 +01001171 "As soon as enough measurements available (1 in our case), perform\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001172 "handover. Afterwards the old cell becomes congested and the new\n"
1173 "cell is not. Do not perform handover until new measurements are\n"
1174 "received.\n",
1175
1176 /* two cells, first in congested, but no handover */
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001177 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001178 "set-min-free", "0", "TCH/F", "4",
1179 "set-min-free", "0", "TCH/H", "4",
1180 "create-ms", "0", "TCH/F", "AMR",
1181 "congestion-check",
1182 "expect-no-chan",
1183
1184 /* send measurement and trigger congestion check */
1185 "meas-rep", "0", "20","0", "1","0","20",
1186 "expect-no-chan",
1187 "congestion-check",
1188 "expect-chan", "1", "1",
1189 "ack-chan",
1190 "expect-ho", "0", "1",
1191 "ho-complete",
1192
1193 /* congest the first cell and remove congestion from second cell */
1194 "set-min-free", "0", "TCH/F", "0",
1195 "set-min-free", "0", "TCH/H", "0",
1196 "set-min-free", "1", "TCH/F", "4",
1197 "set-min-free", "1", "TCH/H", "4",
1198
1199 /* no handover until measurements applied */
1200 "congestion-check",
1201 "expect-no-chan",
1202 "meas-rep", "0", "20","0", "1","0","20",
1203 "expect-no-chan",
1204 "congestion-check",
1205 "expect-chan", "0", "1",
1206 "ack-chan",
1207 "expect-ho", "1", "1",
1208 "ho-complete",
1209 NULL
1210};
1211
1212static char *test_case_25[] = {
1213 "1",
1214
1215 "Stay in better cell\n\n"
1216 "There are many neighbor cells, but only the current cell is the best\n"
1217 "cell, so no handover is performed\n",
1218
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001219 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001220 "create-ms", "0", "TCH/F", "AMR",
1221 "meas-rep", "0", "30","0",
1222 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1223 "expect-no-chan",
1224 NULL
1225};
1226
1227static char *test_case_26[] = {
1228 "1",
1229
1230 "Handover to best better cell\n\n"
1231 "The best neighbor cell is selected\n",
1232
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001233 "create-n-bts", "7",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001234 "create-ms", "0", "TCH/F", "AMR",
1235 "meas-rep", "0", "10","0",
1236 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1237 "expect-chan", "5", "1",
1238 "ack-chan",
1239 "expect-ho", "0", "1",
1240 "ho-complete",
1241 NULL
1242};
1243
1244static char *test_case_27[] = {
1245 "2",
1246
1247 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1248 "There is only one BTS. The TCH/H slots are congested. Since\n"
1249 "assignment is performed to less-congested TCH/F, the candidate with\n"
1250 "the worst RX level is chosen. (So far like test 22.)\n"
1251 "After that, trigger more congestion checks to ensure stability.\n",
1252
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001253 "create-n-bts", "1",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001254 "set-min-free", "0", "TCH/F", "2",
1255 "set-min-free", "0", "TCH/H", "4",
1256 "create-ms", "0", "TCH/H", "AMR",
1257 "create-ms", "0", "TCH/H", "AMR",
1258 "create-ms", "0", "TCH/H", "AMR",
1259 "meas-rep", "0", "30","0", "0",
1260 "meas-rep", "1", "34","0", "0",
1261 "meas-rep", "2", "20","0", "0",
1262 "expect-no-chan",
1263 "congestion-check",
1264 "expect-chan", "0", "1",
1265 "ack-chan",
1266 "expect-ho", "0", "6",
1267 "ho-complete",
1268 "congestion-check",
1269 "expect-chan", "0", "2",
1270 "ack-chan",
1271 "expect-ho", "0", "5",
1272 "ho-complete",
1273 "congestion-check",
1274 "expect-no-chan",
1275 "congestion-check",
1276 "expect-no-chan",
1277 NULL
1278};
1279
1280static char *test_case_28[] = {
1281 "2",
1282
1283 "Handover to congested cell, if RX quality is below minimum\n\n"
1284 "The better neighbor cell is congested, so no handover is performed.\n"
1285 "If the RX quality of the current cell drops below minimum acceptable\n"
1286 "level, the handover is performed. It is also required that 10\n"
1287 "resports are received, before RX quality is checked.\n",
1288
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001289 "create-n-bts", "2",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001290 "create-ms", "0", "TCH/F", "AMR",
1291 "set-min-free", "1", "TCH/F", "4",
1292 "set-min-free", "1", "TCH/H", "4",
1293 "meas-rep", "0", "30","6", "1","0","40",
1294 "expect-no-chan",
1295 "meas-rep", "0", "30","6", "1","0","40",
1296 "expect-no-chan",
1297 "meas-rep", "0", "30","6", "1","0","40",
1298 "expect-no-chan",
1299 "meas-rep", "0", "30","6", "1","0","40",
1300 "expect-no-chan",
1301 "meas-rep", "0", "30","6", "1","0","40",
1302 "expect-no-chan",
1303 "meas-rep", "0", "30","6", "1","0","40",
1304 "expect-no-chan",
1305 "meas-rep", "0", "30","6", "1","0","40",
1306 "expect-no-chan",
1307 "meas-rep", "0", "30","6", "1","0","40",
1308 "expect-no-chan",
1309 "meas-rep", "0", "30","6", "1","0","40",
1310 "expect-no-chan",
1311 "meas-rep", "0", "30","6", "1","0","40",
1312 "expect-chan", "1", "1",
1313 "ack-chan",
1314 "expect-ho", "0", "1",
1315 "ho-complete",
1316 NULL
1317};
1318
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001319static char *test_case_29[] = {
1320 "2",
1321
1322 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1323 "One BTS, and TCH/F are considered congested, TCH/H are not.\n"
1324 ,
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001325 "create-n-bts", "1",
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001326 "set-min-free", "0", "TCH/F", "3",
1327 "set-min-free", "0", "TCH/H", "0",
1328 "create-ms", "0", "TCH/F", "AMR",
1329 "create-ms", "0", "TCH/F", "AMR",
1330 "create-ms", "0", "TCH/H", "AMR",
1331 "meas-rep", "0", "30","0", "1","0","30",
1332 "expect-no-chan",
1333 "congestion-check",
1334 "expect-chan", "0", "5",
1335 "ack-chan",
1336 "expect-ho", "0", "1",
1337 "ho-complete",
1338 NULL
1339};
1340
1341
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001342static char **test_cases[] = {
1343 test_case_0,
1344 test_case_1,
1345 test_case_2,
1346 test_case_3,
1347 test_case_4,
1348 test_case_5,
1349 test_case_6,
1350 test_case_7,
1351 test_case_8,
1352 test_case_9,
1353 test_case_10,
1354 test_case_11,
1355 test_case_12,
1356 test_case_13,
1357 test_case_14,
1358 test_case_15,
1359 test_case_16,
1360 test_case_17,
1361 test_case_18,
1362 test_case_19,
1363 test_case_20,
1364 test_case_21,
1365 test_case_22,
1366 test_case_23,
1367 test_case_24,
1368 test_case_25,
1369 test_case_26,
1370 test_case_27,
1371 test_case_28,
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001372 test_case_29,
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001373};
1374
1375static const struct log_info_cat log_categories[] = {
1376 [DHO] = {
1377 .name = "DHO",
1378 .description = "Hand-Over Process",
1379 .color = "\033[1;38m",
1380 .enabled = 1, .loglevel = LOGL_DEBUG,
1381 },
1382 [DHODEC] = {
1383 .name = "DHODEC",
1384 .description = "Hand-Over Decision",
1385 .color = "\033[1;38m",
1386 .enabled = 1, .loglevel = LOGL_DEBUG,
1387 },
1388 [DMEAS] = {
1389 .name = "DMEAS",
1390 .description = "Radio Measurement Processing",
1391 .enabled = 1, .loglevel = LOGL_DEBUG,
1392 },
1393 [DREF] = {
1394 .name = "DREF",
1395 .description = "Reference Counting",
1396 .enabled = 1, .loglevel = LOGL_DEBUG,
1397 },
1398 [DRSL] = {
1399 .name = "DRSL",
Keithd925c7c2018-04-16 13:40:07 +02001400 .description = "A-bis Radio Signalling Link (RSL)",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001401 .color = "\033[1;35m",
1402 .enabled = 1, .loglevel = LOGL_DEBUG,
1403 },
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001404 [DRR] = {
1405 .name = "DRR",
1406 .description = "RR",
1407 .color = "\033[1;35m",
1408 .enabled = 1, .loglevel = LOGL_DEBUG,
1409 },
1410 [DRLL] = {
1411 .name = "DRLL",
1412 .description = "RLL",
1413 .color = "\033[1;35m",
1414 .enabled = 1, .loglevel = LOGL_DEBUG,
1415 },
Harald Welte3561bd42018-01-28 03:04:16 +01001416 [DMSC] = {
1417 .name = "DMSC",
1418 .description = "Mobile Switching Center",
1419 .enabled = 1, .loglevel = LOGL_DEBUG,
1420 },
Neels Hofmeyr3c5612f2018-07-11 19:53:39 +02001421 [DCHAN] = {
1422 .name = "DCHAN",
1423 .description = "lchan FSM",
1424 .color = "\033[1;32m",
1425 .enabled = 1, .loglevel = LOGL_DEBUG,
1426 },
1427 [DTS] = {
1428 .name = "DTS",
1429 .description = "timeslot FSM",
1430 .color = "\033[1;31m",
1431 .enabled = 1, .loglevel = LOGL_DEBUG,
1432 },
1433 [DAS] = {
1434 .name = "DAS",
1435 .description = "assignment FSM",
1436 .color = "\033[1;33m",
1437 .enabled = 1, .loglevel = LOGL_DEBUG,
1438 },
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001439};
1440
1441const struct log_info log_info = {
1442 .cat = log_categories,
1443 .num_cat = ARRAY_SIZE(log_categories),
1444};
1445
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001446struct gsm_bts *bts_by_num_str(const char *num_str)
1447{
1448 struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, atoi(num_str));
1449 OSMO_ASSERT(bts);
1450 return bts;
1451}
1452
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001453int main(int argc, char **argv)
1454{
1455 char **test_case;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001456 struct gsm_lchan *lchan[256];
1457 int lchan_num = 0;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001458 int i;
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001459 int algorithm;
Neels Hofmeyr00727552018-02-21 14:33:15 +01001460 int test_case_i;
1461 int last_test_i;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001462
Neels Hofmeyre3416182018-03-05 05:31:14 +01001463 ctx = talloc_named_const(NULL, 0, "handover_test");
1464 msgb_talloc_ctx_init(ctx, 0);
1465
Neels Hofmeyr00727552018-02-21 14:33:15 +01001466 test_case_i = argc > 1? atoi(argv[1]) : -1;
1467 last_test_i = ARRAY_SIZE(test_cases) - 1;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001468
Neels Hofmeyr00727552018-02-21 14:33:15 +01001469 if (test_case_i < 0 || test_case_i > last_test_i) {
1470 for (i = 0; i <= last_test_i; i++) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001471 printf("Test #%d (algorithm %s):\n%s\n", i,
1472 test_cases[i][0], test_cases[i][1]);
1473 }
Neels Hofmeyr00727552018-02-21 14:33:15 +01001474 printf("\nPlease specify test case number 0..%d\n", last_test_i);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001475 return EXIT_FAILURE;
1476 }
1477
Neels Hofmeyre3416182018-03-05 05:31:14 +01001478 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001479
1480 log_set_print_category(osmo_stderr_target, 1);
1481 log_set_print_category_hex(osmo_stderr_target, 0);
1482 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001483 osmo_fsm_log_addr(false);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001484
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001485 bsc_network_alloc();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001486 if (!bsc_gsmnet)
1487 exit(1);
1488
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001489 ts_fsm_init();
1490 lchan_fsm_init();
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001491 bsc_subscr_conn_fsm_init();
1492 handover_fsm_init();
1493
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001494 ho_set_algorithm(bsc_gsmnet->ho, 2);
1495 ho_set_ho_active(bsc_gsmnet->ho, true);
1496 ho_set_hodec2_as_active(bsc_gsmnet->ho, true);
1497 ho_set_hodec2_min_rxlev(bsc_gsmnet->ho, -100);
1498 ho_set_hodec2_rxlev_avg_win(bsc_gsmnet->ho, 1);
1499 ho_set_hodec2_rxlev_neigh_avg_win(bsc_gsmnet->ho, 1);
1500 ho_set_hodec2_rxqual_avg_win(bsc_gsmnet->ho, 10);
1501 ho_set_hodec2_pwr_hysteresis(bsc_gsmnet->ho, 3);
1502 ho_set_hodec2_pwr_interval(bsc_gsmnet->ho, 1);
1503 ho_set_hodec2_afs_bias_rxlev(bsc_gsmnet->ho, 0);
1504 ho_set_hodec2_min_rxqual(bsc_gsmnet->ho, 5);
1505 ho_set_hodec2_afs_bias_rxqual(bsc_gsmnet->ho, 0);
1506 ho_set_hodec2_max_distance(bsc_gsmnet->ho, 9999);
1507 ho_set_hodec2_ho_max(bsc_gsmnet->ho, 9999);
1508 ho_set_hodec2_penalty_max_dist(bsc_gsmnet->ho, 300);
1509 ho_set_hodec2_penalty_failed_ho(bsc_gsmnet->ho, 60);
1510 ho_set_hodec2_penalty_failed_as(bsc_gsmnet->ho, 60);
1511
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +07001512 /* We don't really need any specific model here */
1513 bts_model_unknown_init();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001514
Neels Hofmeyr00727552018-02-21 14:33:15 +01001515 test_case = test_cases[test_case_i];
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001516
1517 fprintf(stderr, "--------------------\n");
1518 fprintf(stderr, "Performing the following test %d (algorithm %s):\n%s",
Neels Hofmeyr00727552018-02-21 14:33:15 +01001519 test_case_i, test_case[0], test_case[1]);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001520 algorithm = atoi(test_case[0]);
1521 test_case += 2;
1522 fprintf(stderr, "--------------------\n");
1523
1524 /* Disable the congestion check timer, we will trigger manually. */
1525 bsc_gsmnet->hodec2.congestion_check_interval_s = 0;
1526
1527 handover_decision_1_init();
1528 hodec2_init(bsc_gsmnet);
1529
1530 while (*test_case) {
Neels Hofmeyr4942da82020-11-12 22:58:17 +01001531 if (!strcmp(*test_case, "create-n-bts")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001532 int n = atoi(test_case[1]);
1533 fprintf(stderr, "- Creating %d BTS (one TRX each, "
1534 "TS(1-4) are TCH/F, TS(5-6) are TCH/H)\n", n);
1535 for (i = 0; i < n; i++)
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001536 create_bts(1, bts_default_ts);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001537 test_case += 2;
1538 } else
1539 if (!strcmp(*test_case, "as-enable")) {
1540 fprintf(stderr, "- Set assignment enable state at "
1541 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001542 ho_set_hodec2_as_active(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001543 test_case += 3;
1544 } else
1545 if (!strcmp(*test_case, "ho-enable")) {
1546 fprintf(stderr, "- Set handover enable state at "
1547 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001548 ho_set_ho_active(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001549 test_case += 3;
1550 } else
1551 if (!strcmp(*test_case, "afs-rxlev-improve")) {
1552 fprintf(stderr, "- Set afs RX level improvement at "
1553 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001554 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 +01001555 test_case += 3;
1556 } else
1557 if (!strcmp(*test_case, "afs-rxqual-improve")) {
1558 fprintf(stderr, "- Set afs RX quality improvement at "
1559 "BTS %s to %s\n", test_case[1], test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001560 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 +01001561 test_case += 3;
1562 } else
1563 if (!strcmp(*test_case, "set-min-free")) {
1564 fprintf(stderr, "- Setting minimum required free %s "
1565 "slots at BTS %s to %s\n", test_case[2],
1566 test_case[1], test_case[3]);
1567 if (!strcmp(test_case[2], "TCH/F"))
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001568 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 +01001569 else
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001570 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 +01001571 test_case += 4;
1572 } else
1573 if (!strcmp(*test_case, "set-max-ho")) {
1574 fprintf(stderr, "- Setting maximum parallel handovers "
1575 "at BTS %s to %s\n", test_case[1],
1576 test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001577 ho_set_hodec2_ho_max( 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, "set-max-ta")) {
1581 fprintf(stderr, "- Setting maximum timing advance "
1582 "at BTS %s to %s\n", test_case[1],
1583 test_case[2]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001584 ho_set_hodec2_max_distance(bts_by_num_str(test_case[1])->ho, atoi(test_case[2]));
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001585 test_case += 3;
1586 } else
1587 if (!strcmp(*test_case, "create-ms")) {
1588 fprintf(stderr, "- Creating mobile #%d at BTS %s on "
1589 "%s with %s codec\n", lchan_num, test_case[1],
1590 test_case[2], test_case[3]);
Neels Hofmeyrb5a107d2020-11-12 23:00:08 +01001591 lchan[lchan_num] = create_lchan(bts_by_num_str(test_case[1]),
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001592 !strcmp(test_case[2], "TCH/F"), test_case[3]);
1593 if (!lchan[lchan_num]) {
1594 printf("Failed to create lchan!\n");
1595 return EXIT_FAILURE;
1596 }
1597 fprintf(stderr, " * New MS is at BTS %d TS %d\n",
1598 lchan[lchan_num]->ts->trx->bts->nr,
1599 lchan[lchan_num]->ts->nr);
1600 lchan_num++;
1601 test_case += 4;
1602 } else
1603 if (!strcmp(*test_case, "set-ta")) {
1604 fprintf(stderr, "- Setting maximum timing advance "
1605 "at MS %s to %s\n", test_case[1],
1606 test_case[2]);
1607 meas_ta_ms = atoi(test_case[2]);
1608 test_case += 3;
1609 } else
1610 if (!strcmp(*test_case, "meas-rep")) {
1611 /* meas-rep <lchan-nr> <rxlev> <rxqual> <nr-of-neighbors> [<cell-idx> <rxlev> [...]] */
1612 int n = atoi(test_case[4]);
1613 struct gsm_lchan *lc = lchan[atoi(test_case[1])];
1614 fprintf(stderr, "- Sending measurement report from "
1615 "mobile #%s (rxlev=%s, rxqual=%s)\n",
1616 test_case[1], test_case[2], test_case[3]);
1617 meas_dl_rxlev = atoi(test_case[2]);
1618 meas_dl_rxqual = atoi(test_case[3]);
1619 meas_num_nc = n;
1620 test_case += 5;
1621 for (i = 0; i < n; i++) {
1622 int nr = atoi(test_case[0]);
1623 /* since our bts is not in the list of neighbor
1624 * cells, we need to shift */
1625 if (nr >= lc->ts->trx->bts->nr)
1626 nr++;
1627 fprintf(stderr, " * Neighbor cell #%s, actual "
1628 "BTS %d (rxlev=%s)\n", test_case[0], nr,
1629 test_case[1]);
1630 meas_bcch_f_nc[i] = atoi(test_case[0]);
1631 /* bts number, not counting our own */
1632 meas_rxlev_nc[i] = atoi(test_case[1]);
1633 meas_bsic_nc[i] = 0x3f;
1634 test_case += 2;
1635 }
1636 got_chan_req = 0;
1637 gen_meas_rep(lc);
1638 } else
1639 if (!strcmp(*test_case, "congestion-check")) {
1640 fprintf(stderr, "- Triggering congestion check\n");
1641 got_chan_req = 0;
1642 if (algorithm == 2)
1643 hodec2_congestion_check(bsc_gsmnet);
1644 test_case += 1;
1645 } else
1646 if (!strcmp(*test_case, "expect-chan")) {
1647 fprintf(stderr, "- Expecting channel request at BTS %s "
1648 "TS %s\n", test_case[1], test_case[2]);
1649 if (!got_chan_req) {
1650 printf("Test failed, because no channel was "
1651 "requested\n");
1652 return EXIT_FAILURE;
1653 }
1654 fprintf(stderr, " * Got channel request at BTS %d "
1655 "TS %d\n", chan_req_lchan->ts->trx->bts->nr,
1656 chan_req_lchan->ts->nr);
1657 if (chan_req_lchan->ts->trx->bts->nr
1658 != atoi(test_case[1])) {
1659 printf("Test failed, because channel was not "
1660 "requested on expected BTS\n");
1661 return EXIT_FAILURE;
1662 }
1663 if (chan_req_lchan->ts->nr != atoi(test_case[2])) {
1664 printf("Test failed, because channel was not "
1665 "requested on expected TS\n");
1666 return EXIT_FAILURE;
1667 }
1668 test_case += 3;
1669 } else
1670 if (!strcmp(*test_case, "expect-no-chan")) {
1671 fprintf(stderr, "- Expecting no channel request\n");
1672 if (got_chan_req) {
1673 fprintf(stderr, " * Got channel request at "
1674 "BTS %d TS %d\n",
1675 chan_req_lchan->ts->trx->bts->nr,
1676 chan_req_lchan->ts->nr);
1677 printf("Test failed, because channel was "
1678 "requested\n");
1679 return EXIT_FAILURE;
1680 }
1681 fprintf(stderr, " * Got no channel request\n");
1682 test_case += 1;
1683 } else
1684 if (!strcmp(*test_case, "expect-ho")) {
1685 fprintf(stderr, "- Expecting handover/assignment "
1686 "request at BTS %s TS %s\n", test_case[1],
1687 test_case[2]);
1688 if (!got_ho_req) {
1689 printf("Test failed, because no handover was "
1690 "requested\n");
1691 return EXIT_FAILURE;
1692 }
1693 fprintf(stderr, " * Got handover/assignment request at "
1694 "BTS %d TS %d\n",
1695 ho_req_lchan->ts->trx->bts->nr,
1696 ho_req_lchan->ts->nr);
1697 if (ho_req_lchan->ts->trx->bts->nr
1698 != atoi(test_case[1])) {
1699 printf("Test failed, because "
1700 "handover/assignment was not commanded "
1701 "at the expected BTS\n");
1702 return EXIT_FAILURE;
1703 }
1704 if (ho_req_lchan->ts->nr != atoi(test_case[2])) {
1705 printf("Test failed, because "
1706 "handover/assignment was not commanded "
1707 "at the expected TS\n");
1708 return EXIT_FAILURE;
1709 }
1710 test_case += 3;
1711 } else
1712 if (!strcmp(*test_case, "ack-chan")) {
1713 fprintf(stderr, "- Acknowledging channel request\n");
1714 if (!got_chan_req) {
1715 printf("Cannot ack channel, because no "
1716 "request\n");
1717 return EXIT_FAILURE;
1718 }
1719 test_case += 1;
1720 got_ho_req = 0;
1721 send_chan_act_ack(chan_req_lchan, 1);
1722 } else
1723 if (!strcmp(*test_case, "ho-complete")) {
1724 fprintf(stderr, "- Acknowledging handover/assignment "
1725 "request\n");
1726 if (!got_chan_req) {
1727 printf("Cannot ack handover/assignment, "
1728 "because no chan request\n");
1729 return EXIT_FAILURE;
1730 }
1731 if (!got_ho_req) {
1732 printf("Cannot ack handover/assignment, "
1733 "because no ho request\n");
1734 return EXIT_FAILURE;
1735 }
1736 test_case += 1;
1737 got_chan_req = 0;
1738 got_ho_req = 0;
1739 /* switch lchan */
1740 for (i = 0; i < lchan_num; i++) {
1741 if (lchan[i] == ho_req_lchan) {
1742 fprintf(stderr, " * MS %d changes from "
1743 "BTS=%d TS=%d to BTS=%d "
1744 "TS=%d\n", i,
1745 lchan[i]->ts->trx->bts->nr,
1746 lchan[i]->ts->nr,
1747 chan_req_lchan->ts->trx->bts->nr,
1748 chan_req_lchan->ts->nr);
1749 lchan[i] = chan_req_lchan;
1750 }
1751 }
1752 send_ho_complete(chan_req_lchan, true);
1753 } else
1754 if (!strcmp(*test_case, "ho-failed")) {
1755 fprintf(stderr, "- Making handover fail\n");
1756 if (!got_chan_req) {
1757 printf("Cannot fail handover, because no chan "
1758 "request\n");
1759 return EXIT_FAILURE;
1760 }
1761 test_case += 1;
1762 got_chan_req = 0;
1763 got_ho_req = 0;
1764 send_ho_complete(ho_req_lchan, false);
1765 } else
1766 if (!strcmp(*test_case, "print")) {
1767 fprintf(stderr, "\n%s\n\n", test_case[1]);
1768 test_case += 2;
1769 } else {
1770 printf("Unknown test command '%s', please fix!\n",
1771 *test_case);
1772 return EXIT_FAILURE;
1773 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001774
1775 {
1776 /* Help the lchan out of releasing states */
1777 struct gsm_bts *bts;
1778 llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
1779 struct gsm_bts_trx *trx;
1780 llist_for_each_entry(trx, &bts->trx_list, list) {
1781 int ts_nr;
1782 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
1783 struct gsm_lchan *lchan;
1784 ts_for_each_lchan(lchan, &trx->ts[ts_nr]) {
1785
1786 if (lchan->fi && lchan->fi->state == LCHAN_ST_WAIT_BEFORE_RF_RELEASE) {
1787 osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_WAIT_RF_RELEASE_ACK, 0, 0);
1788 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RSL_RF_CHAN_REL_ACK, 0);
1789 }
1790 }
1791 }
1792 }
1793 }
1794 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001795 }
1796
1797 for (i = 0; i < lchan_num; i++) {
1798 struct gsm_subscriber_connection *conn = lchan[i]->conn;
1799 lchan[i]->conn = NULL;
1800 conn->lchan = NULL;
Harald Welte3561bd42018-01-28 03:04:16 +01001801 osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REGULAR, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001802 }
1803
1804 fprintf(stderr, "--------------------\n");
1805
1806 printf("Test OK\n");
1807
1808 fprintf(stderr, "--------------------\n");
1809
Neels Hofmeyre3416182018-03-05 05:31:14 +01001810 talloc_free(ctx);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001811 return EXIT_SUCCESS;
1812}
1813
1814void rtp_socket_free() {}
1815void rtp_send_frame() {}
1816void rtp_socket_upstream() {}
1817void rtp_socket_create() {}
1818void rtp_socket_connect() {}
1819void rtp_socket_proxy() {}
1820void trau_mux_unmap() {}
1821void trau_mux_map_lchan() {}
1822void trau_recv_lchan() {}
1823void trau_send_frame() {}
Harald Welte3561bd42018-01-28 03:04:16 +01001824int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
1825int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
Vadim Yanitskiy6a26e2c2020-08-26 18:49:08 +07001826void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, uint8_t dlci, enum gsm0808_cause cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001827void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr) {}
Neels Hofmeyr2001dd62020-09-11 23:35:28 +00001828int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_channel)
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001829{ return 0; }
Neels Hofmeyr86ce1052020-09-18 02:49:32 +02001830int bsc_paging_start(struct bsc_paging_params *params)
1831{ return 0; }
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001832void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) {}
1833void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001834void bsc_cm_update(struct gsm_subscriber_connection *conn,
1835 const uint8_t *cm2, uint8_t cm2_len,
1836 const uint8_t *cm3, uint8_t cm3_len) {}
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001837struct gsm0808_handover_required;
1838int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell_id_list2 *target_cells)
1839{ return 0; }
1840int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, struct msgb *rr_ho_command)
1841{ return 0; }
1842int bsc_tx_bssmap_ho_detect(struct gsm_subscriber_connection *conn) { return 0; }
1843enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn,
1844 struct gsm_lchan *lchan) { return HO_RESULT_OK; }
1845void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001846void osmo_bsc_sigtran_tx_reset(void) {}
Neels Hofmeyre95b92b2020-10-09 17:18:29 +02001847void osmo_bsc_sigtran_tx_reset_ack(void) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001848void osmo_bsc_sigtran_reset(void) {}
1849void bssmap_reset_alloc(void) {}
1850void bssmap_reset_is_conn_ready(void) {}