blob: cc533863a767560c647cce74b68ddd85e0a50147 [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 Hofmeyr2f58de52020-11-12 22:51:11 +0100177static struct gsm_bts *create_bts()
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100178{
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100179 static int arfcn = 870;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100180 struct gsm_bts *bts;
181 struct e1inp_sign_link *rsl_link;
182 int i;
183
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +0700184 bts = bsc_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_UNKNOWN, 0x3f);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100185 if (!bts) {
186 printf("No resource for bts1\n");
187 return NULL;
188 }
189
190 bts->location_area_code = 23;
Neels Hofmeyr2f58de52020-11-12 22:51:11 +0100191 bts->c0->arfcn = arfcn++;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100192
193 bts->codec.efr = 1;
194 bts->codec.hr = 1;
195 bts->codec.amr = 1;
196
Neels Hofmeyre3416182018-03-05 05:31:14 +0100197 rsl_link = talloc_zero(ctx, struct e1inp_sign_link);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100198 rsl_link->trx = bts->c0;
199 bts->c0->rsl_link = rsl_link;
200
201 bts->c0->mo.nm_state.operational = NM_OPSTATE_ENABLED;
202 bts->c0->mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200203 bts->c0->mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100204 bts->c0->bb_transc.mo.nm_state.operational = NM_OPSTATE_ENABLED;
205 bts->c0->bb_transc.mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200206 bts->c0->bb_transc.mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100207
208 /* 4 full rate and 4 half rate channels */
209 for (i = 1; i <= 6; i++) {
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200210 bts->c0->ts[i].pchan_from_config = (i < 5) ? GSM_PCHAN_TCH_F : GSM_PCHAN_TCH_H;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100211 bts->c0->ts[i].mo.nm_state.operational = NM_OPSTATE_ENABLED;
212 bts->c0->ts[i].mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200213 bts->c0->ts[i].mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200214 }
215
216 for (i = 0; i < ARRAY_SIZE(bts->c0->ts); i++) {
217 /* make sure ts->lchans[] get initialized */
Neels Hofmeyrbcdbfb72018-07-26 20:33:15 +0200218 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_RSL_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200219 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_OML_READY, 0);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100220 }
Neels Hofmeyr780f0282020-11-12 22:51:58 +0100221
222 for (i = 0; i < bsc_gsmnet->num_bts; i++) {
223 if (gsm_generate_si(gsm_bts_num(bsc_gsmnet, i), SYSINFO_TYPE_2) <= 0)
224 fprintf(stderr, "Error generating SI2\n");
225 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100226 return bts;
227}
228
229void create_conn(struct gsm_lchan *lchan)
230{
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200231 static unsigned int next_imsi = 0;
232 char imsi[sizeof(lchan->conn->bsub->imsi)];
233 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Welte3561bd42018-01-28 03:04:16 +0100234 struct gsm_subscriber_connection *conn;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200235 struct mgcp_client *fake_mgcp_client = (void*)talloc_zero(net, int);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200236
237 conn = bsc_subscr_con_allocate(net);
Harald Welte3561bd42018-01-28 03:04:16 +0100238
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200239 conn->user_plane.mgw_endpoint = osmo_mgcpc_ep_alloc(conn->fi,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200240 GSCON_EV_FORGET_MGW_ENDPOINT,
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200241 fake_mgcp_client,
242 net->mgw.tdefs,
243 "test",
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200244 "fake endpoint");
Alexander Chemeris69ba8be2020-05-10 22:48:01 +0300245 conn->sccp.msc = osmo_msc_data_alloc(net, 0);
Harald Welte3561bd42018-01-28 03:04:16 +0100246
247 lchan->conn = conn;
248 conn->lchan = lchan;
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200249
250 /* Make up a new IMSI for this test, for logging the subscriber */
251 next_imsi ++;
252 snprintf(imsi, sizeof(imsi), "%06u", next_imsi);
Neels Hofmeyr86a1dca2020-09-15 01:03:58 +0000253 lchan->conn->bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers, imsi, BSUB_USE_CONN);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200254
Harald Welte3561bd42018-01-28 03:04:16 +0100255 /* kick the FSM from INIT through to the ACTIVE state */
Neels Hofmeyrd1e7d392020-09-27 23:34:57 +0200256 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MO_COMPL_L3, NULL);
Harald Welte3561bd42018-01-28 03:04:16 +0100257 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100258}
259
260/* create lchan */
261struct gsm_lchan *create_lchan(struct gsm_bts *bts, int full_rate, char *codec)
262{
263 struct gsm_lchan *lchan;
264
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200265 lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100266 if (!lchan) {
267 printf("No resource for lchan\n");
268 exit(EXIT_FAILURE);
269 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200270
271 /* serious hack into osmo_fsm */
272 lchan->fi->state = LCHAN_ST_ESTABLISHED;
273 lchan->ts->fi->state = TS_ST_IN_USE;
274 LOG_LCHAN(lchan, LOGL_DEBUG, "activated by handover_test.c\n");
275
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100276 create_conn(lchan);
277 if (!strcasecmp(codec, "FR") && full_rate)
278 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
279 else if (!strcasecmp(codec, "HR") && !full_rate)
280 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
281 else if (!strcasecmp(codec, "EFR") && full_rate)
282 lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100283 else if (!strcasecmp(codec, "AMR")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100284 lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100285 lchan->activate.info.s15_s0 = 0x0002;
286 } else {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100287 printf("Given codec unknown\n");
288 exit(EXIT_FAILURE);
289 }
290
291 lchan->conn->codec_list = (struct gsm0808_speech_codec_list){
292 .codec = {
293 { .fi=true, .type=GSM0808_SCT_FR1, },
294 { .fi=true, .type=GSM0808_SCT_FR2, },
295 { .fi=true, .type=GSM0808_SCT_FR3, },
296 { .fi=true, .type=GSM0808_SCT_HR1, },
297 { .fi=true, .type=GSM0808_SCT_HR3, },
298 },
299 .len = 5,
300 };
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100301
302 return lchan;
303}
304
305/* parse channel request */
306
307static int got_chan_req = 0;
308static struct gsm_lchan *chan_req_lchan = NULL;
309
310static int parse_chan_act(struct gsm_lchan *lchan, uint8_t *data)
311{
312 chan_req_lchan = lchan;
313 return 0;
314}
315
316static int parse_chan_rel(struct gsm_lchan *lchan, uint8_t *data)
317{
318 chan_req_lchan = lchan;
319 return 0;
320}
321
322/* parse handover request */
323
324static int got_ho_req = 0;
325static struct gsm_lchan *ho_req_lchan = NULL;
326
327static int parse_ho_command(struct gsm_lchan *lchan, uint8_t *data, int len)
328{
329 struct gsm48_hdr *gh = (struct gsm48_hdr *) data;
330 struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) gh->data;
331 int arfcn;
332 struct gsm_bts *neigh;
333
334 switch (gh->msg_type) {
335 case GSM48_MT_RR_HANDO_CMD:
336 arfcn = (ho->cell_desc.arfcn_hi << 8) | ho->cell_desc.arfcn_lo;
337
338 /* look up trx. since every dummy bts uses different arfcn and
339 * only one trx, it is simple */
340 llist_for_each_entry(neigh, &bsc_gsmnet->bts_list, list) {
341 if (neigh->c0->arfcn != arfcn)
342 continue;
343 ho_req_lchan = lchan;
344 return 0;
345 }
346 break;
347 case GSM48_MT_RR_ASS_CMD:
348 ho_req_lchan = lchan;
349 return 0;
350 break;
351 default:
352 fprintf(stderr, "Error, expecting HO or AS command\n");
353 return -EINVAL;
354 }
355
356 return -1;
357}
358
359/* send channel activation ack */
360static void send_chan_act_ack(struct gsm_lchan *lchan, int act)
361{
362 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
363 struct abis_rsl_dchan_hdr *dh;
364
365 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
366 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
367 dh->c.msg_type = (act) ? RSL_MT_CHAN_ACTIV_ACK : RSL_MT_RF_CHAN_REL_ACK;
368 dh->ie_chan = RSL_IE_CHAN_NR;
369 dh->chan_nr = gsm_lchan2chan_nr(lchan);
370
371 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
372 msg->l2h = (unsigned char *)dh;
373
374 abis_rsl_rcvmsg(msg);
375}
376
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200377/* Send RLL Est Ind for SAPI[0] */
378static void send_est_ind(struct gsm_lchan *lchan)
379{
380 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
381 struct abis_rsl_rll_hdr *rh;
382 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
383
384 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
385 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
386 rh->c.msg_type = RSL_MT_EST_IND;
387 rh->ie_chan = RSL_IE_CHAN_NR;
388 rh->chan_nr = chan_nr;
389 rh->ie_link_id = RSL_IE_LINK_IDENT;
390 rh->link_id = 0x00;
391
392 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
393 msg->l2h = (unsigned char *)rh;
394
395 abis_rsl_rcvmsg(msg);
396}
397
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100398/* send handover complete */
399static void send_ho_complete(struct gsm_lchan *lchan, bool success)
400{
401 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
402 struct abis_rsl_rll_hdr *rh;
403 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
404 uint8_t *buf;
405 struct gsm48_hdr *gh;
406 struct gsm48_ho_cpl *hc;
407
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200408 send_est_ind(lchan);
Neels Hofmeyrac85b342018-07-12 21:23:26 +0200409 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RTP_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200410
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100411 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
412 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
413 rh->c.msg_type = RSL_MT_DATA_IND;
414 rh->ie_chan = RSL_IE_CHAN_NR;
415 rh->chan_nr = chan_nr;
416 rh->ie_link_id = RSL_IE_LINK_IDENT;
417 rh->link_id = 0x00;
418
419 buf = msgb_put(msg, 3);
420 buf[0] = RSL_IE_L3_INFO;
421 buf[1] = (sizeof(*gh) + sizeof(*hc)) >> 8;
422 buf[2] = (sizeof(*gh) + sizeof(*hc)) & 0xff;
423
424 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
425 hc = (struct gsm48_ho_cpl *) msgb_put(msg, sizeof(*hc));
426
427 gh->proto_discr = GSM48_PDISC_RR;
428 gh->msg_type =
429 success ? GSM48_MT_RR_HANDO_COMPL : GSM48_MT_RR_HANDO_FAIL;
430
431 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
432 msg->l2h = (unsigned char *)rh;
433 msg->l3h = (unsigned char *)gh;
434
435 abis_rsl_rcvmsg(msg);
436}
437
Neels Hofmeyr1d7473c2018-03-05 21:53:18 +0100438/* override, requires '-Wl,--wrap=abis_rsl_sendmsg'.
439 * Catch RSL messages sent towards the BTS. */
440int __real_abis_rsl_sendmsg(struct msgb *msg);
441int __wrap_abis_rsl_sendmsg(struct msgb *msg)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100442{
443 struct abis_rsl_dchan_hdr *dh = (struct abis_rsl_dchan_hdr *) msg->data;
444 struct e1inp_sign_link *sign_link = msg->dst;
445 int rc;
446 struct gsm_lchan *lchan = rsl_lchan_lookup(sign_link->trx, dh->chan_nr, &rc);
447
448 if (rc) {
449 printf("rsl_lchan_lookup() failed\n");
450 exit(1);
451 }
452
453 switch (dh->c.msg_type) {
454 case RSL_MT_CHAN_ACTIV:
455 rc = parse_chan_act(lchan, dh->data);
456 if (rc == 0)
457 got_chan_req = 1;
458 break;
459 case RSL_MT_RF_CHAN_REL:
460 rc = parse_chan_rel(lchan, dh->data);
461 if (rc == 0)
462 send_chan_act_ack(chan_req_lchan, 0);
463 break;
464 case RSL_MT_DATA_REQ:
465 rc = parse_ho_command(lchan, msg->l3h, msgb_l3len(msg));
466 if (rc == 0)
467 got_ho_req = 1;
468 break;
469 case RSL_MT_IPAC_CRCX:
470 break;
Neels Hofmeyr5b1a7d12018-11-06 22:24:07 +0100471 case RSL_MT_DEACTIVATE_SACCH:
472 break;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100473 default:
474 printf("unknown rsl message=0x%x\n", dh->c.msg_type);
475 }
476 return 0;
477}
478
479/* test cases */
480
481static char *test_case_0[] = {
482 "2",
483
484 "Stay in better cell\n\n"
485 "There are many neighbor cells, but only the current cell is the best\n"
486 "cell, so no handover is performed\n",
487
488 "create-bts", "7",
489 "create-ms", "0", "TCH/F", "AMR",
490 "meas-rep", "0", "30","0",
491 "6","0","20","1","21","2","18","3","20","4","23","5","19",
492 "expect-no-chan",
493 NULL
494};
495
496static char *test_case_1[] = {
497 "2",
498
499 "Handover to best better cell\n\n"
500 "The best neighbor cell is selected\n",
501
502 "create-bts", "7",
503 "create-ms", "0", "TCH/F", "AMR",
504 "meas-rep", "0", "10","0",
505 "6","0","20","1","21","2","18","3","20","4","23","5","19",
506 "expect-chan", "5", "1",
507 "ack-chan",
508 "expect-ho", "0", "1",
509 "ho-complete",
510 NULL
511};
512
513static char *test_case_2[] = {
514 "2",
515
516 "Handover and Assignment must be enabled\n\n"
517 "This test will start with disabled assignment and handover. A\n"
518 "better neighbor cell (assignment enabled) will not be selected and \n"
519 "also no assignment from TCH/H to TCH/F to improve quality. There\n"
520 "will be no handover nor assignment. After enabling assignment on the\n"
521 "current cell, the MS will assign to TCH/F. After enabling handover\n"
522 "in the current cell, but disabling in the neighbor cell, handover\n"
523 "will not be performed, until it is enabled in the neighbor cell too.\n",
524
525 "create-bts", "2",
526 "afs-rxlev-improve", "0", "5",
527 "create-ms", "0", "TCH/H", "AMR",
528 "as-enable", "0", "0",
529 "ho-enable", "0", "0",
530 "meas-rep", "0", "0","0", "1","0","30",
531 "expect-no-chan",
532 "as-enable", "0", "1",
533 "meas-rep", "0", "0","0", "1","0","30",
534 "expect-chan", "0", "1",
535 "ack-chan",
536 "expect-ho", "0", "5",
537 "ho-complete",
538 "ho-enable", "0", "1",
539 "ho-enable", "1", "0",
540 "meas-rep", "0", "0","0", "1","0","30",
541 "expect-no-chan",
542 "ho-enable", "1", "1",
543 "meas-rep", "0", "0","0", "1","0","30",
544 "expect-chan", "1", "1",
545 "ack-chan",
546 "expect-ho", "0", "1",
547 "ho-complete",
548 NULL
549};
550
551static char *test_case_3[] = {
552 "2",
553
554 "Penalty timer must not run\n\n"
555 "The MS will try to handover to a better cell, but this will fail.\n"
556 "Even though the cell is still better, handover will not be performed\n"
557 "due to penalty timer after handover failure\n",
558
559 "create-bts", "2",
560 "create-ms", "0", "TCH/F", "AMR",
561 "meas-rep", "0", "20","0", "1","0","30",
562 "expect-chan", "1", "1",
563 "ack-chan",
564 "expect-ho", "0", "1",
565 "ho-failed",
566 "meas-rep", "0", "20","0", "1","0","30",
567 "expect-no-chan",
568 NULL
569};
570
571static char *test_case_4[] = {
572 "2",
573
574 "TCH/H keeping with HR codec\n\n"
575 "The MS is using half rate V1 codec, but the better cell is congested\n"
576 "at TCH/H slots. As the congestion is removed, the handover takes\n"
577 "place.\n",
578
579 "create-bts", "2",
580 "set-min-free", "1", "TCH/H", "4",
581 "create-ms", "0", "TCH/H", "HR",
582 "meas-rep", "0", "20","0", "1","0","30",
583 "expect-no-chan",
584 "set-min-free", "1", "TCH/H", "3",
585 "meas-rep", "0", "20","0", "1","0","30",
586 "expect-chan", "1", "5",
587 "ack-chan",
588 "expect-ho", "0", "5",
589 "ho-complete",
590 NULL
591};
592
593static char *test_case_5[] = {
594 "2",
595
596 "TCH/F keeping with FR codec\n\n"
597 "The MS is using full rate V1 codec, but the better cell is congested\n"
598 "at TCH/F slots. As the congestion is removed, the handover takes\n"
599 "place.\n",
600
601 "create-bts", "2",
602 "set-min-free", "1", "TCH/F", "4",
603 "create-ms", "0", "TCH/F", "FR",
604 "meas-rep", "0", "20","0", "1","0","30",
605 "expect-no-chan",
606 "set-min-free", "1", "TCH/F", "3",
607 "meas-rep", "0", "20","0", "1","0","30",
608 "expect-chan", "1", "1",
609 "ack-chan",
610 "expect-ho", "0", "1",
611 "ho-complete",
612 NULL
613};
614
615static char *test_case_6[] = {
616 "2",
617
618 "TCH/F keeping with EFR codec\n\n"
619 "The MS is using full rate V2 codec, but the better cell is congested\n"
620 "at TCH/F slots. As the congestion is removed, the handover takes\n"
621 "place.\n",
622
623 "create-bts", "2",
624 "set-min-free", "1", "TCH/F", "4",
625 "create-ms", "0", "TCH/F", "EFR",
626 "meas-rep", "0", "20","0", "1","0","30",
627 "expect-no-chan",
628 "set-min-free", "1", "TCH/F", "3",
629 "meas-rep", "0", "20","0", "1","0","30",
630 "expect-chan", "1", "1",
631 "ack-chan",
632 "expect-ho", "0", "1",
633 "ho-complete",
634 NULL
635};
636
637static char *test_case_7[] = {
638 "2",
639
640 "TCH/F to TCH/H changing with AMR codec\n\n"
641 "The MS is using AMR V3 codec, the better cell is congested at TCH/F\n"
642 "slots. The handover is performed to non-congested TCH/H slots.\n",
643
644 "create-bts", "2",
645 "set-min-free", "1", "TCH/F", "4",
646 "create-ms", "0", "TCH/F", "AMR",
647 "meas-rep", "0", "20","0", "1","0","30",
648 "expect-chan", "1", "5",
649 "ack-chan",
650 "expect-ho", "0", "1",
651 "ho-complete",
652 NULL
653};
654
655static char *test_case_8[] = {
656 "2",
657
658 "No handover to a cell with no slots available\n\n"
659 "If no slot is available, no handover is performed\n",
660
661 "create-bts", "2",
662 "create-ms", "0", "TCH/F", "AMR",
663 "create-ms", "1", "TCH/F", "AMR",
664 "create-ms", "1", "TCH/F", "AMR",
665 "create-ms", "1", "TCH/F", "AMR",
666 "create-ms", "1", "TCH/F", "AMR",
667 "create-ms", "1", "TCH/H", "AMR",
668 "create-ms", "1", "TCH/H", "AMR",
669 "create-ms", "1", "TCH/H", "AMR",
670 "create-ms", "1", "TCH/H", "AMR",
671 "meas-rep", "0", "0","0", "1","0","30",
672 "expect-no-chan",
673 NULL
674};
675
676static char *test_case_9[] = {
677 "2",
678
679 "No more parallel handovers, if max_unsync_ho is defined\n\n"
680 "There are tree mobiles that want to handover, but only two can do\n"
681 "it at a time, because the maximum number is limited to two.\n",
682
683 "create-bts", "2",
684 "set-max-ho", "1", "2",
685 "create-ms", "0", "TCH/F", "AMR",
686 "create-ms", "0", "TCH/F", "AMR",
687 "create-ms", "0", "TCH/F", "AMR",
688 "meas-rep", "0", "0","0", "1","0","30",
689 "expect-chan", "1", "1",
690 "meas-rep", "1", "0","0", "1","0","30",
691 "expect-chan", "1", "2",
692 "meas-rep", "2", "0","0", "1","0","30",
693 "expect-no-chan",
694 NULL
695};
696
697static char *test_case_10[] = {
698 "2",
699
700 "Hysteresis\n\n"
701 "If neighbor cell is better, handover is only performed if the\n"
Martin Haukea29affd2019-11-13 22:10:41 +0100702 "amount of improvement is greater or equal hyteresis\n",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100703
704 "create-bts", "2",
705 "create-ms", "0", "TCH/F", "AMR",
706 "meas-rep", "0", "27","0", "1","0","30",
707 "expect-no-chan",
708 "meas-rep", "0", "26","0", "1","0","30",
709 "expect-chan", "1", "1",
710 "ack-chan",
711 "expect-ho", "0", "1",
712 "ho-complete",
713 NULL
714};
715
716static char *test_case_11[] = {
717 "2",
718
719 "No Hysteresis and minimum RX level\n\n"
720 "If current cell's RX level is below mimium level, handover must be\n"
721 "performed, no matter of the hysteresis. First do not perform\n"
722 "handover to better neighbor cell, because the hysteresis is not\n"
723 "met. Second do not perform handover because better neighbor cell is\n"
724 "below minimum RX level. Third perform handover because current cell\n"
725 "is below minimum RX level, even if the better neighbor cell (minimum\n"
726 "RX level reached) does not meet the hysteresis.\n",
727
728 "create-bts", "2",
729 "create-ms", "0", "TCH/F", "AMR",
730 "meas-rep", "0", "10","0", "1","0","11",
731 "expect-no-chan",
732 "meas-rep", "0", "8","0", "1","0","9",
733 "expect-no-chan",
734 "meas-rep", "0", "9","0", "1","0","10",
735 "expect-chan", "1", "1",
736 "ack-chan",
737 "expect-ho", "0", "1",
738 "ho-complete",
739 NULL
740};
741
742static char *test_case_12[] = {
743 "2",
744
745 "No handover to congested cell\n\n"
746 "The better neighbor cell is congested, so no handover is performed.\n"
747 "After the congestion is over, handover will be performed.\n",
748
749 "create-bts", "2",
750 "create-ms", "0", "TCH/F", "AMR",
751 "set-min-free", "1", "TCH/F", "4",
752 "set-min-free", "1", "TCH/H", "4",
753 "meas-rep", "0", "20","0", "1","0","30",
754 "expect-no-chan",
755 "set-min-free", "1", "TCH/F", "3",
756 "set-min-free", "1", "TCH/H", "3",
757 "meas-rep", "0", "20","0", "1","0","30",
758 "expect-chan", "1", "1",
759 "ack-chan",
760 "expect-ho", "0", "1",
761 "ho-complete",
762 NULL
763};
764
765static char *test_case_13[] = {
766 "2",
767
768 "Handover to balance congestion\n\n"
769 "The current and the better cell are congested, so no handover is\n"
770 "performed. This is because handover would congest the neighbor cell\n"
771 "more. After congestion raises in the current cell, the handover is\n"
772 "performed to balance congestion\n",
773
774 "create-bts", "2",
775 "create-ms", "0", "TCH/F", "AMR",
776 "set-min-free", "0", "TCH/F", "4",
777 "set-min-free", "0", "TCH/H", "4",
778 "set-min-free", "1", "TCH/F", "4",
779 "set-min-free", "1", "TCH/H", "4",
780 "meas-rep", "0", "20","0", "1","0","30",
781 "expect-no-chan",
782 "create-ms", "0", "TCH/F", "AMR",
783 "meas-rep", "0", "20","0", "1","0","30",
784 "expect-chan", "1", "1",
785 "ack-chan",
786 "expect-ho", "0", "1",
787 "ho-complete",
788 NULL
789};
790
791static char *test_case_14[] = {
792 "2",
793
794 "Handover to congested cell, if RX level is below minimum\n\n"
795 "The better neighbor cell is congested, so no handover is performed.\n"
796 "If the RX level of the current cell drops below minimum acceptable\n"
797 "level, the handover is performed.\n",
798
799 "create-bts", "2",
800 "create-ms", "0", "TCH/F", "AMR",
801 "set-min-free", "1", "TCH/F", "4",
802 "set-min-free", "1", "TCH/H", "4",
803 "meas-rep", "0", "10","0", "1","0","30",
804 "expect-no-chan",
805 "meas-rep", "0", "9","0", "1","0","30",
806 "expect-chan", "1", "1",
807 "ack-chan",
808 "expect-ho", "0", "1",
809 "ho-complete",
810 NULL
811};
812
813static char *test_case_15[] = {
814 "2",
815
816 "Handover to cell with worse RXLEV, if RXQUAL is below minimum\n\n"
817 "The neighbor cell has worse RXLEV, so no handover is performed.\n"
818 "If the RXQUAL of the current cell drops below minimum acceptable\n"
819 "level, the handover is performed. It is also required that 10\n"
820 "reports are received, before RXQUAL is checked.\n",
821 /* (See also test 28, which tests for RXQUAL triggering HO to congested cell.) */
822 /* TODO: bad RXQUAL may want to prefer assignment within the same cell to avoid interference.
Martin Haukea29affd2019-11-13 22:10:41 +0100823 * See Performance Enhancements in a Frequency Hopping GSM Network (Nielsen Wigard 2002), Chapter
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100824 * 2.1.1, "Interference" in the list of triggers on p.157. */
825
826 "create-bts", "2",
827 "create-ms", "0", "TCH/F", "AMR",
828 "meas-rep", "0", "40","6", "1","0","30",
829 "expect-no-chan",
830 "meas-rep", "0", "40","6", "1","0","30",
831 "expect-no-chan",
832 "meas-rep", "0", "40","6", "1","0","30",
833 "expect-no-chan",
834 "meas-rep", "0", "40","6", "1","0","30",
835 "expect-no-chan",
836 "meas-rep", "0", "40","6", "1","0","30",
837 "expect-no-chan",
838 "meas-rep", "0", "40","6", "1","0","30",
839 "expect-no-chan",
840 "meas-rep", "0", "40","6", "1","0","30",
841 "expect-no-chan",
842 "meas-rep", "0", "40","6", "1","0","30",
843 "expect-no-chan",
844 "meas-rep", "0", "40","6", "1","0","30",
845 "expect-no-chan",
846 "meas-rep", "0", "40","6", "1","0","30",
847 "expect-chan", "1", "1",
848 "ack-chan",
849 "expect-ho", "0", "1",
850 "ho-complete",
851 NULL
852};
853
854static char *test_case_16[] = {
855 "2",
856
857 "Handover due to maximum TA exceeded\n\n"
858 "The MS in the current (best) cell has reached maximum allowed timing\n"
859 "advance. No handover is performed until the timing advance exceeds\n"
860 "it. The originating cell is still the best, but no handover is\n"
861 "performed back to that cell, because the penalty timer (due to\n"
862 "maximum allowed timing advance) is running.\n",
863
864 "create-bts", "2",
865 "create-ms", "0", "TCH/F", "AMR",
866 "set-max-ta", "0", "5", /* of cell */
867 "set-ta", "0", "5", /* of ms */
868 "meas-rep", "0", "30","0", "1","0","20",
869 "expect-no-chan",
870 "set-ta", "0", "6", /* of ms */
871 "meas-rep", "0", "30","0", "1","0","20",
872 "expect-chan", "1", "1",
873 "ack-chan",
874 "expect-ho", "0", "1",
875 "ho-complete",
876 "meas-rep", "0", "20","0", "1","0","30",
877 "expect-no-chan",
878 NULL
879};
880
881static char *test_case_17[] = {
882 "2",
883
884 "Congestion check: No congestion\n\n"
885 "Three cells have different number of used slots, but there is no\n"
886 "congestion in any of these cells. No handover is performed.\n",
887
888 "create-bts", "3",
889 "set-min-free", "0", "TCH/F", "2",
890 "set-min-free", "0", "TCH/H", "2",
891 "set-min-free", "1", "TCH/F", "2",
892 "set-min-free", "1", "TCH/H", "2",
893 "set-min-free", "2", "TCH/F", "2",
894 "set-min-free", "2", "TCH/H", "2",
895 "create-ms", "0", "TCH/F", "AMR",
896 "create-ms", "0", "TCH/F", "AMR",
897 "create-ms", "0", "TCH/H", "AMR",
898 "create-ms", "0", "TCH/H", "AMR",
899 "create-ms", "1", "TCH/F", "AMR",
900 "create-ms", "1", "TCH/H", "AMR",
901 "meas-rep", "0", "30","0", "2","0","20","1","20",
902 "expect-no-chan",
903 "meas-rep", "1", "30","0", "2","0","20","1","20",
904 "expect-no-chan",
905 "meas-rep", "2", "30","0", "2","0","20","1","20",
906 "expect-no-chan",
907 "meas-rep", "3", "30","0", "2","0","20","1","20",
908 "expect-no-chan",
909 "meas-rep", "4", "30","0", "2","0","20","1","20",
910 "expect-no-chan",
911 "meas-rep", "5", "30","0", "2","0","20","1","20",
912 "expect-no-chan",
913 "congestion-check",
914 "expect-no-chan",
915 NULL
916};
917
918static char *test_case_18[] = {
919 "2",
920
921 "Congestion check: One out of three cells is congested\n\n"
922 "Three cells have different number of used slots, but there is\n"
923 "congestion at TCH/F in the first cell. Handover is performed with\n"
924 "the best candidate.\n",
925
926 "create-bts", "3",
927 "set-min-free", "0", "TCH/F", "2",
928 "set-min-free", "0", "TCH/H", "2",
929 "set-min-free", "1", "TCH/F", "2",
930 "set-min-free", "1", "TCH/H", "2",
931 "set-min-free", "2", "TCH/F", "2",
932 "set-min-free", "2", "TCH/H", "2",
933 "create-ms", "0", "TCH/F", "AMR",
934 "create-ms", "0", "TCH/F", "AMR",
935 "create-ms", "0", "TCH/F", "AMR",
936 "create-ms", "0", "TCH/H", "AMR",
937 "create-ms", "0", "TCH/H", "AMR",
938 "create-ms", "1", "TCH/F", "AMR",
939 "create-ms", "1", "TCH/H", "AMR",
940 "meas-rep", "0", "30","0", "2","0","20","1","20",
941 "expect-no-chan",
942 "meas-rep", "1", "30","0", "2","0","20","1","20",
943 "expect-no-chan",
944 "meas-rep", "2", "30","0", "2","0","21","1","20",
945 "expect-no-chan",
946 "meas-rep", "3", "30","0", "2","0","20","1","20",
947 "expect-no-chan",
948 "meas-rep", "4", "30","0", "2","0","20","1","20",
949 "expect-no-chan",
950 "meas-rep", "5", "30","0", "2","0","20","1","20",
951 "expect-no-chan",
952 "meas-rep", "6", "30","0", "2","0","20","1","20",
953 "expect-no-chan",
954 "congestion-check",
955 "expect-chan", "1", "2",
956 "ack-chan",
Neels Hofmeyr72d64e72020-11-16 18:07:31 +0100957 "expect-ho", "0", "3", /* best candidate is MS 2 at BTS 0, TS 3 */
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100958 "ho-complete",
959 NULL
960};
961
962static char *test_case_19[] = {
963 "2",
964
965 "Congestion check: Balancing over congested cells\n\n"
Neels Hofmeyr1336d942020-08-10 21:13:55 +0200966 "Two cells are congested, but the second cell is less congested.\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100967 "Handover is performed to solve the congestion.\n",
968
969 "create-bts", "2",
970 "set-min-free", "0", "TCH/F", "4",
971 "set-min-free", "1", "TCH/F", "4",
972 "create-ms", "0", "TCH/F", "FR",
973 "create-ms", "0", "TCH/F", "FR",
974 "create-ms", "0", "TCH/F", "FR",
975 "create-ms", "1", "TCH/F", "FR",
976 "meas-rep", "0", "30","0", "1","0","20",
977 "expect-no-chan",
978 "meas-rep", "1", "30","0", "1","0","21",
979 "expect-no-chan",
980 "meas-rep", "2", "30","0", "1","0","20",
981 "expect-no-chan",
982 "meas-rep", "3", "30","0", "1","0","20",
983 "expect-no-chan",
984 "congestion-check",
985 "expect-chan", "1", "2",
986 "ack-chan",
987 "expect-ho", "0", "2", /* best candidate is MS 1 at BTS 0, TS 2 */
988 "ho-complete",
989 NULL
990};
991
992static char *test_case_20[] = {
993 "2",
994
995 "Congestion check: Solving congestion by handover TCH/F -> TCH/H\n\n"
996 "Two BTS, one MS in the first congested BTS must handover to\n"
997 "non-congested TCH/H of second BTS, in order to solve congestion\n",
998 "create-bts", "2",
999 "set-min-free", "0", "TCH/F", "4",
1000 "set-min-free", "0", "TCH/H", "4",
1001 "set-min-free", "1", "TCH/F", "4",
1002 "create-ms", "0", "TCH/F", "AMR",
1003 "meas-rep", "0", "30","0", "1","0","30",
1004 "expect-no-chan",
1005 "congestion-check",
1006 "expect-chan", "1", "5",
1007 "ack-chan",
1008 "expect-ho", "0", "1",
1009 "ho-complete",
1010 NULL
1011};
1012
1013static char *test_case_21[] = {
1014 "2",
1015
1016 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1017 "Two BTS, one MS in the first congested BTS must handover to\n"
1018 "less-congested TCH/H of second BTS, in order to balance congestion\n",
1019 "create-bts", "2",
1020 "set-min-free", "0", "TCH/F", "4",
1021 "set-min-free", "0", "TCH/H", "4",
1022 "set-min-free", "1", "TCH/F", "4",
1023 "set-min-free", "1", "TCH/H", "4",
1024 "create-ms", "0", "TCH/F", "AMR",
1025 "create-ms", "0", "TCH/F", "AMR",
1026 "create-ms", "0", "TCH/H", "AMR",
1027 "meas-rep", "0", "30","0", "1","0","30",
1028 "expect-no-chan",
1029 "congestion-check",
1030 "expect-chan", "1", "1",
1031 "ack-chan",
1032 "expect-ho", "0", "1",
1033 "ho-complete",
1034 NULL
1035};
1036
1037static char *test_case_22[] = {
1038 "2",
1039
1040 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1041 "There is only one BTS. The TCH/H slots are congested. Since\n"
1042 "assignment is performed to less-congested TCH/F, the candidate with\n"
1043 "the worst RX level is chosen.\n",
1044
1045 "create-bts", "1",
1046 "set-min-free", "0", "TCH/F", "4",
1047 "set-min-free", "0", "TCH/H", "4",
1048 "create-ms", "0", "TCH/H", "AMR",
1049 "create-ms", "0", "TCH/H", "AMR",
1050 "create-ms", "0", "TCH/H", "AMR",
1051 "meas-rep", "0", "30","0", "0",
1052 "meas-rep", "1", "34","0", "0",
1053 "meas-rep", "2", "20","0", "0",
1054 "expect-no-chan",
1055 "congestion-check",
1056 "expect-chan", "0", "1",
1057 "ack-chan",
1058 "expect-ho", "0", "6",
1059 "ho-complete",
1060 NULL
1061};
1062
1063static char *test_case_23[] = {
1064 "2",
1065
1066 "Story: 'A neighbor is your friend'\n",
1067
1068 "create-bts", "3",
1069
1070 "print",
1071 "Andreas is driving along the coast, on a sunny june afternoon.\n"
1072 "Suddenly he is getting a call from his friend and neighbor Axel.\n"
1073 "\n"
1074 "What happens: Two MS are created, #0 for Axel, #1 for Andreas.",
1075 /* Axel */
1076 "create-ms", "2", "TCH/F", "AMR",
1077 /* andreas */
1078 "create-ms", "0", "TCH/F", "AMR",
1079 "meas-rep", "1", "40","0", "1","0","30",
1080 "expect-no-chan",
1081
1082 "print",
1083 "Axel asks Andreas if he would like to join them for a barbecue.\n"
1084 "Axel's house is right in the neighborhood and the weather is fine.\n"
1085 "Andreas agrees, so he drives to a close store to buy some barbecue\n"
1086 "skewers.\n"
1087 "\n"
1088 "What happens: While driving, a different cell (mounted atop the\n"
1089 "store) becomes better.",
1090 /* drive to bts 1 */
1091 "meas-rep", "1", "20","0", "1","0","35",
1092 "expect-chan", "1", "1",
1093 "ack-chan",
1094 "expect-ho", "0", "1",
1095 "ho-complete",
1096
1097 "print",
1098 "While Andreas is walking into the store, Axel asks, if he could also\n"
1099 "bring some beer. Andreas has problems understanding him: \"I have a\n"
1100 "bad reception here. The cell tower is right atop the store, but poor\n"
1101 "coverage inside. Can you repeat please?\"\n"
1102 "\n"
1103 "What happens: Inside the store the close cell is so bad, that\n"
1104 "handover back to the previous cell is required.",
1105 /* bts 1 becomes bad, so bts 0 helps out */
1106 "meas-rep", "1", "5","0", "1","0","20",
1107 "expect-chan", "0", "1",
1108 "ack-chan",
1109 "expect-ho", "1", "1",
1110 "ho-complete",
1111
1112 "print",
1113 "After Andreas bought skewers and beer, he leaves the store.\n"
1114 "\n"
1115 "What happens: Outside the store the close cell is better again, so\n"
1116 "handover back to the that cell is performed.",
1117 /* bts 1 becomes better again */
1118 "meas-rep", "1", "20","0", "1","0","35",
1119 "expect-chan", "1", "1",
1120 "ack-chan",
1121 "expect-ho", "0", "1",
1122 "ho-complete",
1123
1124 "print",
1125 /* bts 2 becomes better */
1126 "Andreas drives down to the lake where Axel's house is.\n"
1127 "\n"
1128 "What happens: There is a small cell at Axel's house, which becomes\n"
1129 "better, because the current cell has no good comverage at the lake.",
1130 "meas-rep", "1", "14","0", "2","0","2","1","63",
1131 "expect-chan", "2", "2",
1132 "ack-chan",
1133 "expect-ho", "1", "1",
1134 "ho-complete",
1135
1136 "print",
1137 "Andreas wonders why he still has good radio coverage: \"Last time it\n"
1138 "was so bad\". Axel says: \"I installed a pico cell in my house,\n"
1139 "now we can use our mobile phones down here at the lake.\"",
1140
1141 NULL
1142};
1143
1144static char *test_case_24[] = {
1145 "2",
1146 "No (or not enough) measurements for handover\n\n"
1147 "Do not solve congestion in cell, because there is no measurement.\n"
Martin Haukea29affd2019-11-13 22:10:41 +01001148 "As soon as enough measurements available (1 in our case), perform\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001149 "handover. Afterwards the old cell becomes congested and the new\n"
1150 "cell is not. Do not perform handover until new measurements are\n"
1151 "received.\n",
1152
1153 /* two cells, first in congested, but no handover */
1154 "create-bts", "2",
1155 "set-min-free", "0", "TCH/F", "4",
1156 "set-min-free", "0", "TCH/H", "4",
1157 "create-ms", "0", "TCH/F", "AMR",
1158 "congestion-check",
1159 "expect-no-chan",
1160
1161 /* send measurement and trigger congestion check */
1162 "meas-rep", "0", "20","0", "1","0","20",
1163 "expect-no-chan",
1164 "congestion-check",
1165 "expect-chan", "1", "1",
1166 "ack-chan",
1167 "expect-ho", "0", "1",
1168 "ho-complete",
1169
1170 /* congest the first cell and remove congestion from second cell */
1171 "set-min-free", "0", "TCH/F", "0",
1172 "set-min-free", "0", "TCH/H", "0",
1173 "set-min-free", "1", "TCH/F", "4",
1174 "set-min-free", "1", "TCH/H", "4",
1175
1176 /* no handover until measurements applied */
1177 "congestion-check",
1178 "expect-no-chan",
1179 "meas-rep", "0", "20","0", "1","0","20",
1180 "expect-no-chan",
1181 "congestion-check",
1182 "expect-chan", "0", "1",
1183 "ack-chan",
1184 "expect-ho", "1", "1",
1185 "ho-complete",
1186 NULL
1187};
1188
1189static char *test_case_25[] = {
1190 "1",
1191
1192 "Stay in better cell\n\n"
1193 "There are many neighbor cells, but only the current cell is the best\n"
1194 "cell, so no handover is performed\n",
1195
1196 "create-bts", "7",
1197 "create-ms", "0", "TCH/F", "AMR",
1198 "meas-rep", "0", "30","0",
1199 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1200 "expect-no-chan",
1201 NULL
1202};
1203
1204static char *test_case_26[] = {
1205 "1",
1206
1207 "Handover to best better cell\n\n"
1208 "The best neighbor cell is selected\n",
1209
1210 "create-bts", "7",
1211 "create-ms", "0", "TCH/F", "AMR",
1212 "meas-rep", "0", "10","0",
1213 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1214 "expect-chan", "5", "1",
1215 "ack-chan",
1216 "expect-ho", "0", "1",
1217 "ho-complete",
1218 NULL
1219};
1220
1221static char *test_case_27[] = {
1222 "2",
1223
1224 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1225 "There is only one BTS. The TCH/H slots are congested. Since\n"
1226 "assignment is performed to less-congested TCH/F, the candidate with\n"
1227 "the worst RX level is chosen. (So far like test 22.)\n"
1228 "After that, trigger more congestion checks to ensure stability.\n",
1229
1230 "create-bts", "1",
1231 "set-min-free", "0", "TCH/F", "2",
1232 "set-min-free", "0", "TCH/H", "4",
1233 "create-ms", "0", "TCH/H", "AMR",
1234 "create-ms", "0", "TCH/H", "AMR",
1235 "create-ms", "0", "TCH/H", "AMR",
1236 "meas-rep", "0", "30","0", "0",
1237 "meas-rep", "1", "34","0", "0",
1238 "meas-rep", "2", "20","0", "0",
1239 "expect-no-chan",
1240 "congestion-check",
1241 "expect-chan", "0", "1",
1242 "ack-chan",
1243 "expect-ho", "0", "6",
1244 "ho-complete",
1245 "congestion-check",
1246 "expect-chan", "0", "2",
1247 "ack-chan",
1248 "expect-ho", "0", "5",
1249 "ho-complete",
1250 "congestion-check",
1251 "expect-no-chan",
1252 "congestion-check",
1253 "expect-no-chan",
1254 NULL
1255};
1256
1257static char *test_case_28[] = {
1258 "2",
1259
1260 "Handover to congested cell, if RX quality is below minimum\n\n"
1261 "The better neighbor cell is congested, so no handover is performed.\n"
1262 "If the RX quality of the current cell drops below minimum acceptable\n"
1263 "level, the handover is performed. It is also required that 10\n"
1264 "resports are received, before RX quality is checked.\n",
1265
1266 "create-bts", "2",
1267 "create-ms", "0", "TCH/F", "AMR",
1268 "set-min-free", "1", "TCH/F", "4",
1269 "set-min-free", "1", "TCH/H", "4",
1270 "meas-rep", "0", "30","6", "1","0","40",
1271 "expect-no-chan",
1272 "meas-rep", "0", "30","6", "1","0","40",
1273 "expect-no-chan",
1274 "meas-rep", "0", "30","6", "1","0","40",
1275 "expect-no-chan",
1276 "meas-rep", "0", "30","6", "1","0","40",
1277 "expect-no-chan",
1278 "meas-rep", "0", "30","6", "1","0","40",
1279 "expect-no-chan",
1280 "meas-rep", "0", "30","6", "1","0","40",
1281 "expect-no-chan",
1282 "meas-rep", "0", "30","6", "1","0","40",
1283 "expect-no-chan",
1284 "meas-rep", "0", "30","6", "1","0","40",
1285 "expect-no-chan",
1286 "meas-rep", "0", "30","6", "1","0","40",
1287 "expect-no-chan",
1288 "meas-rep", "0", "30","6", "1","0","40",
1289 "expect-chan", "1", "1",
1290 "ack-chan",
1291 "expect-ho", "0", "1",
1292 "ho-complete",
1293 NULL
1294};
1295
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001296static char *test_case_29[] = {
1297 "2",
1298
1299 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1300 "One BTS, and TCH/F are considered congested, TCH/H are not.\n"
1301 ,
1302 "create-bts", "1",
1303 "set-min-free", "0", "TCH/F", "3",
1304 "set-min-free", "0", "TCH/H", "0",
1305 "create-ms", "0", "TCH/F", "AMR",
1306 "create-ms", "0", "TCH/F", "AMR",
1307 "create-ms", "0", "TCH/H", "AMR",
1308 "meas-rep", "0", "30","0", "1","0","30",
1309 "expect-no-chan",
1310 "congestion-check",
1311 "expect-chan", "0", "5",
1312 "ack-chan",
1313 "expect-ho", "0", "1",
1314 "ho-complete",
1315 NULL
1316};
1317
1318
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001319static char **test_cases[] = {
1320 test_case_0,
1321 test_case_1,
1322 test_case_2,
1323 test_case_3,
1324 test_case_4,
1325 test_case_5,
1326 test_case_6,
1327 test_case_7,
1328 test_case_8,
1329 test_case_9,
1330 test_case_10,
1331 test_case_11,
1332 test_case_12,
1333 test_case_13,
1334 test_case_14,
1335 test_case_15,
1336 test_case_16,
1337 test_case_17,
1338 test_case_18,
1339 test_case_19,
1340 test_case_20,
1341 test_case_21,
1342 test_case_22,
1343 test_case_23,
1344 test_case_24,
1345 test_case_25,
1346 test_case_26,
1347 test_case_27,
1348 test_case_28,
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001349 test_case_29,
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001350};
1351
1352static const struct log_info_cat log_categories[] = {
1353 [DHO] = {
1354 .name = "DHO",
1355 .description = "Hand-Over Process",
1356 .color = "\033[1;38m",
1357 .enabled = 1, .loglevel = LOGL_DEBUG,
1358 },
1359 [DHODEC] = {
1360 .name = "DHODEC",
1361 .description = "Hand-Over Decision",
1362 .color = "\033[1;38m",
1363 .enabled = 1, .loglevel = LOGL_DEBUG,
1364 },
1365 [DMEAS] = {
1366 .name = "DMEAS",
1367 .description = "Radio Measurement Processing",
1368 .enabled = 1, .loglevel = LOGL_DEBUG,
1369 },
1370 [DREF] = {
1371 .name = "DREF",
1372 .description = "Reference Counting",
1373 .enabled = 1, .loglevel = LOGL_DEBUG,
1374 },
1375 [DRSL] = {
1376 .name = "DRSL",
Keithd925c7c2018-04-16 13:40:07 +02001377 .description = "A-bis Radio Signalling Link (RSL)",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001378 .color = "\033[1;35m",
1379 .enabled = 1, .loglevel = LOGL_DEBUG,
1380 },
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001381 [DRR] = {
1382 .name = "DRR",
1383 .description = "RR",
1384 .color = "\033[1;35m",
1385 .enabled = 1, .loglevel = LOGL_DEBUG,
1386 },
1387 [DRLL] = {
1388 .name = "DRLL",
1389 .description = "RLL",
1390 .color = "\033[1;35m",
1391 .enabled = 1, .loglevel = LOGL_DEBUG,
1392 },
Harald Welte3561bd42018-01-28 03:04:16 +01001393 [DMSC] = {
1394 .name = "DMSC",
1395 .description = "Mobile Switching Center",
1396 .enabled = 1, .loglevel = LOGL_DEBUG,
1397 },
Neels Hofmeyr3c5612f2018-07-11 19:53:39 +02001398 [DCHAN] = {
1399 .name = "DCHAN",
1400 .description = "lchan FSM",
1401 .color = "\033[1;32m",
1402 .enabled = 1, .loglevel = LOGL_DEBUG,
1403 },
1404 [DTS] = {
1405 .name = "DTS",
1406 .description = "timeslot FSM",
1407 .color = "\033[1;31m",
1408 .enabled = 1, .loglevel = LOGL_DEBUG,
1409 },
1410 [DAS] = {
1411 .name = "DAS",
1412 .description = "assignment FSM",
1413 .color = "\033[1;33m",
1414 .enabled = 1, .loglevel = LOGL_DEBUG,
1415 },
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001416};
1417
1418const struct log_info log_info = {
1419 .cat = log_categories,
1420 .num_cat = ARRAY_SIZE(log_categories),
1421};
1422
1423int main(int argc, char **argv)
1424{
1425 char **test_case;
1426 struct gsm_bts *bts[256];
1427 int bts_num = 0;
1428 struct gsm_lchan *lchan[256];
1429 int lchan_num = 0;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001430 int i;
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001431 int algorithm;
Neels Hofmeyr00727552018-02-21 14:33:15 +01001432 int test_case_i;
1433 int last_test_i;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001434
Neels Hofmeyre3416182018-03-05 05:31:14 +01001435 ctx = talloc_named_const(NULL, 0, "handover_test");
1436 msgb_talloc_ctx_init(ctx, 0);
1437
Neels Hofmeyr00727552018-02-21 14:33:15 +01001438 test_case_i = argc > 1? atoi(argv[1]) : -1;
1439 last_test_i = ARRAY_SIZE(test_cases) - 1;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001440
Neels Hofmeyr00727552018-02-21 14:33:15 +01001441 if (test_case_i < 0 || test_case_i > last_test_i) {
1442 for (i = 0; i <= last_test_i; i++) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001443 printf("Test #%d (algorithm %s):\n%s\n", i,
1444 test_cases[i][0], test_cases[i][1]);
1445 }
Neels Hofmeyr00727552018-02-21 14:33:15 +01001446 printf("\nPlease specify test case number 0..%d\n", last_test_i);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001447 return EXIT_FAILURE;
1448 }
1449
Neels Hofmeyre3416182018-03-05 05:31:14 +01001450 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001451
1452 log_set_print_category(osmo_stderr_target, 1);
1453 log_set_print_category_hex(osmo_stderr_target, 0);
1454 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001455 osmo_fsm_log_addr(false);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001456
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001457 bsc_network_alloc();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001458 if (!bsc_gsmnet)
1459 exit(1);
1460
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001461 ts_fsm_init();
1462 lchan_fsm_init();
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001463 bsc_subscr_conn_fsm_init();
1464 handover_fsm_init();
1465
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001466 ho_set_algorithm(bsc_gsmnet->ho, 2);
1467 ho_set_ho_active(bsc_gsmnet->ho, true);
1468 ho_set_hodec2_as_active(bsc_gsmnet->ho, true);
1469 ho_set_hodec2_min_rxlev(bsc_gsmnet->ho, -100);
1470 ho_set_hodec2_rxlev_avg_win(bsc_gsmnet->ho, 1);
1471 ho_set_hodec2_rxlev_neigh_avg_win(bsc_gsmnet->ho, 1);
1472 ho_set_hodec2_rxqual_avg_win(bsc_gsmnet->ho, 10);
1473 ho_set_hodec2_pwr_hysteresis(bsc_gsmnet->ho, 3);
1474 ho_set_hodec2_pwr_interval(bsc_gsmnet->ho, 1);
1475 ho_set_hodec2_afs_bias_rxlev(bsc_gsmnet->ho, 0);
1476 ho_set_hodec2_min_rxqual(bsc_gsmnet->ho, 5);
1477 ho_set_hodec2_afs_bias_rxqual(bsc_gsmnet->ho, 0);
1478 ho_set_hodec2_max_distance(bsc_gsmnet->ho, 9999);
1479 ho_set_hodec2_ho_max(bsc_gsmnet->ho, 9999);
1480 ho_set_hodec2_penalty_max_dist(bsc_gsmnet->ho, 300);
1481 ho_set_hodec2_penalty_failed_ho(bsc_gsmnet->ho, 60);
1482 ho_set_hodec2_penalty_failed_as(bsc_gsmnet->ho, 60);
1483
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +07001484 /* We don't really need any specific model here */
1485 bts_model_unknown_init();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001486
Neels Hofmeyr00727552018-02-21 14:33:15 +01001487 test_case = test_cases[test_case_i];
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001488
1489 fprintf(stderr, "--------------------\n");
1490 fprintf(stderr, "Performing the following test %d (algorithm %s):\n%s",
Neels Hofmeyr00727552018-02-21 14:33:15 +01001491 test_case_i, test_case[0], test_case[1]);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001492 algorithm = atoi(test_case[0]);
1493 test_case += 2;
1494 fprintf(stderr, "--------------------\n");
1495
1496 /* Disable the congestion check timer, we will trigger manually. */
1497 bsc_gsmnet->hodec2.congestion_check_interval_s = 0;
1498
1499 handover_decision_1_init();
1500 hodec2_init(bsc_gsmnet);
1501
1502 while (*test_case) {
1503 if (!strcmp(*test_case, "create-bts")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001504 int n = atoi(test_case[1]);
1505 fprintf(stderr, "- Creating %d BTS (one TRX each, "
1506 "TS(1-4) are TCH/F, TS(5-6) are TCH/H)\n", n);
1507 for (i = 0; i < n; i++)
Neels Hofmeyr2f58de52020-11-12 22:51:11 +01001508 bts[bts_num + i] = create_bts();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001509 bts_num += n;
1510 test_case += 2;
1511 } else
1512 if (!strcmp(*test_case, "as-enable")) {
1513 fprintf(stderr, "- Set assignment enable state at "
1514 "BTS %s to %s\n", test_case[1], test_case[2]);
1515 ho_set_hodec2_as_active(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1516 test_case += 3;
1517 } else
1518 if (!strcmp(*test_case, "ho-enable")) {
1519 fprintf(stderr, "- Set handover enable state at "
1520 "BTS %s to %s\n", test_case[1], test_case[2]);
1521 ho_set_ho_active(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1522 test_case += 3;
1523 } else
1524 if (!strcmp(*test_case, "afs-rxlev-improve")) {
1525 fprintf(stderr, "- Set afs RX level improvement at "
1526 "BTS %s to %s\n", test_case[1], test_case[2]);
1527 ho_set_hodec2_afs_bias_rxlev(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1528 test_case += 3;
1529 } else
1530 if (!strcmp(*test_case, "afs-rxqual-improve")) {
1531 fprintf(stderr, "- Set afs RX quality improvement at "
1532 "BTS %s to %s\n", test_case[1], test_case[2]);
1533 ho_set_hodec2_afs_bias_rxqual(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1534 test_case += 3;
1535 } else
1536 if (!strcmp(*test_case, "set-min-free")) {
1537 fprintf(stderr, "- Setting minimum required free %s "
1538 "slots at BTS %s to %s\n", test_case[2],
1539 test_case[1], test_case[3]);
1540 if (!strcmp(test_case[2], "TCH/F"))
1541 ho_set_hodec2_tchf_min_slots(bts[atoi(test_case[1])]->ho, atoi(test_case[3]));
1542 else
1543 ho_set_hodec2_tchh_min_slots(bts[atoi(test_case[1])]->ho, atoi(test_case[3]));
1544 test_case += 4;
1545 } else
1546 if (!strcmp(*test_case, "set-max-ho")) {
1547 fprintf(stderr, "- Setting maximum parallel handovers "
1548 "at BTS %s to %s\n", test_case[1],
1549 test_case[2]);
1550 ho_set_hodec2_ho_max( bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1551 test_case += 3;
1552 } else
1553 if (!strcmp(*test_case, "set-max-ta")) {
1554 fprintf(stderr, "- Setting maximum timing advance "
1555 "at BTS %s to %s\n", test_case[1],
1556 test_case[2]);
1557 ho_set_hodec2_max_distance(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1558 test_case += 3;
1559 } else
1560 if (!strcmp(*test_case, "create-ms")) {
1561 fprintf(stderr, "- Creating mobile #%d at BTS %s on "
1562 "%s with %s codec\n", lchan_num, test_case[1],
1563 test_case[2], test_case[3]);
1564 lchan[lchan_num] = create_lchan(bts[atoi(test_case[1])],
1565 !strcmp(test_case[2], "TCH/F"), test_case[3]);
1566 if (!lchan[lchan_num]) {
1567 printf("Failed to create lchan!\n");
1568 return EXIT_FAILURE;
1569 }
1570 fprintf(stderr, " * New MS is at BTS %d TS %d\n",
1571 lchan[lchan_num]->ts->trx->bts->nr,
1572 lchan[lchan_num]->ts->nr);
1573 lchan_num++;
1574 test_case += 4;
1575 } else
1576 if (!strcmp(*test_case, "set-ta")) {
1577 fprintf(stderr, "- Setting maximum timing advance "
1578 "at MS %s to %s\n", test_case[1],
1579 test_case[2]);
1580 meas_ta_ms = atoi(test_case[2]);
1581 test_case += 3;
1582 } else
1583 if (!strcmp(*test_case, "meas-rep")) {
1584 /* meas-rep <lchan-nr> <rxlev> <rxqual> <nr-of-neighbors> [<cell-idx> <rxlev> [...]] */
1585 int n = atoi(test_case[4]);
1586 struct gsm_lchan *lc = lchan[atoi(test_case[1])];
1587 fprintf(stderr, "- Sending measurement report from "
1588 "mobile #%s (rxlev=%s, rxqual=%s)\n",
1589 test_case[1], test_case[2], test_case[3]);
1590 meas_dl_rxlev = atoi(test_case[2]);
1591 meas_dl_rxqual = atoi(test_case[3]);
1592 meas_num_nc = n;
1593 test_case += 5;
1594 for (i = 0; i < n; i++) {
1595 int nr = atoi(test_case[0]);
1596 /* since our bts is not in the list of neighbor
1597 * cells, we need to shift */
1598 if (nr >= lc->ts->trx->bts->nr)
1599 nr++;
1600 fprintf(stderr, " * Neighbor cell #%s, actual "
1601 "BTS %d (rxlev=%s)\n", test_case[0], nr,
1602 test_case[1]);
1603 meas_bcch_f_nc[i] = atoi(test_case[0]);
1604 /* bts number, not counting our own */
1605 meas_rxlev_nc[i] = atoi(test_case[1]);
1606 meas_bsic_nc[i] = 0x3f;
1607 test_case += 2;
1608 }
1609 got_chan_req = 0;
1610 gen_meas_rep(lc);
1611 } else
1612 if (!strcmp(*test_case, "congestion-check")) {
1613 fprintf(stderr, "- Triggering congestion check\n");
1614 got_chan_req = 0;
1615 if (algorithm == 2)
1616 hodec2_congestion_check(bsc_gsmnet);
1617 test_case += 1;
1618 } else
1619 if (!strcmp(*test_case, "expect-chan")) {
1620 fprintf(stderr, "- Expecting channel request at BTS %s "
1621 "TS %s\n", test_case[1], test_case[2]);
1622 if (!got_chan_req) {
1623 printf("Test failed, because no channel was "
1624 "requested\n");
1625 return EXIT_FAILURE;
1626 }
1627 fprintf(stderr, " * Got channel request at BTS %d "
1628 "TS %d\n", chan_req_lchan->ts->trx->bts->nr,
1629 chan_req_lchan->ts->nr);
1630 if (chan_req_lchan->ts->trx->bts->nr
1631 != atoi(test_case[1])) {
1632 printf("Test failed, because channel was not "
1633 "requested on expected BTS\n");
1634 return EXIT_FAILURE;
1635 }
1636 if (chan_req_lchan->ts->nr != atoi(test_case[2])) {
1637 printf("Test failed, because channel was not "
1638 "requested on expected TS\n");
1639 return EXIT_FAILURE;
1640 }
1641 test_case += 3;
1642 } else
1643 if (!strcmp(*test_case, "expect-no-chan")) {
1644 fprintf(stderr, "- Expecting no channel request\n");
1645 if (got_chan_req) {
1646 fprintf(stderr, " * Got channel request at "
1647 "BTS %d TS %d\n",
1648 chan_req_lchan->ts->trx->bts->nr,
1649 chan_req_lchan->ts->nr);
1650 printf("Test failed, because channel was "
1651 "requested\n");
1652 return EXIT_FAILURE;
1653 }
1654 fprintf(stderr, " * Got no channel request\n");
1655 test_case += 1;
1656 } else
1657 if (!strcmp(*test_case, "expect-ho")) {
1658 fprintf(stderr, "- Expecting handover/assignment "
1659 "request at BTS %s TS %s\n", test_case[1],
1660 test_case[2]);
1661 if (!got_ho_req) {
1662 printf("Test failed, because no handover was "
1663 "requested\n");
1664 return EXIT_FAILURE;
1665 }
1666 fprintf(stderr, " * Got handover/assignment request at "
1667 "BTS %d TS %d\n",
1668 ho_req_lchan->ts->trx->bts->nr,
1669 ho_req_lchan->ts->nr);
1670 if (ho_req_lchan->ts->trx->bts->nr
1671 != atoi(test_case[1])) {
1672 printf("Test failed, because "
1673 "handover/assignment was not commanded "
1674 "at the expected BTS\n");
1675 return EXIT_FAILURE;
1676 }
1677 if (ho_req_lchan->ts->nr != atoi(test_case[2])) {
1678 printf("Test failed, because "
1679 "handover/assignment was not commanded "
1680 "at the expected TS\n");
1681 return EXIT_FAILURE;
1682 }
1683 test_case += 3;
1684 } else
1685 if (!strcmp(*test_case, "ack-chan")) {
1686 fprintf(stderr, "- Acknowledging channel request\n");
1687 if (!got_chan_req) {
1688 printf("Cannot ack channel, because no "
1689 "request\n");
1690 return EXIT_FAILURE;
1691 }
1692 test_case += 1;
1693 got_ho_req = 0;
1694 send_chan_act_ack(chan_req_lchan, 1);
1695 } else
1696 if (!strcmp(*test_case, "ho-complete")) {
1697 fprintf(stderr, "- Acknowledging handover/assignment "
1698 "request\n");
1699 if (!got_chan_req) {
1700 printf("Cannot ack handover/assignment, "
1701 "because no chan request\n");
1702 return EXIT_FAILURE;
1703 }
1704 if (!got_ho_req) {
1705 printf("Cannot ack handover/assignment, "
1706 "because no ho request\n");
1707 return EXIT_FAILURE;
1708 }
1709 test_case += 1;
1710 got_chan_req = 0;
1711 got_ho_req = 0;
1712 /* switch lchan */
1713 for (i = 0; i < lchan_num; i++) {
1714 if (lchan[i] == ho_req_lchan) {
1715 fprintf(stderr, " * MS %d changes from "
1716 "BTS=%d TS=%d to BTS=%d "
1717 "TS=%d\n", i,
1718 lchan[i]->ts->trx->bts->nr,
1719 lchan[i]->ts->nr,
1720 chan_req_lchan->ts->trx->bts->nr,
1721 chan_req_lchan->ts->nr);
1722 lchan[i] = chan_req_lchan;
1723 }
1724 }
1725 send_ho_complete(chan_req_lchan, true);
1726 } else
1727 if (!strcmp(*test_case, "ho-failed")) {
1728 fprintf(stderr, "- Making handover fail\n");
1729 if (!got_chan_req) {
1730 printf("Cannot fail handover, because no chan "
1731 "request\n");
1732 return EXIT_FAILURE;
1733 }
1734 test_case += 1;
1735 got_chan_req = 0;
1736 got_ho_req = 0;
1737 send_ho_complete(ho_req_lchan, false);
1738 } else
1739 if (!strcmp(*test_case, "print")) {
1740 fprintf(stderr, "\n%s\n\n", test_case[1]);
1741 test_case += 2;
1742 } else {
1743 printf("Unknown test command '%s', please fix!\n",
1744 *test_case);
1745 return EXIT_FAILURE;
1746 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001747
1748 {
1749 /* Help the lchan out of releasing states */
1750 struct gsm_bts *bts;
1751 llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
1752 struct gsm_bts_trx *trx;
1753 llist_for_each_entry(trx, &bts->trx_list, list) {
1754 int ts_nr;
1755 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
1756 struct gsm_lchan *lchan;
1757 ts_for_each_lchan(lchan, &trx->ts[ts_nr]) {
1758
1759 if (lchan->fi && lchan->fi->state == LCHAN_ST_WAIT_BEFORE_RF_RELEASE) {
1760 osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_WAIT_RF_RELEASE_ACK, 0, 0);
1761 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RSL_RF_CHAN_REL_ACK, 0);
1762 }
1763 }
1764 }
1765 }
1766 }
1767 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001768 }
1769
1770 for (i = 0; i < lchan_num; i++) {
1771 struct gsm_subscriber_connection *conn = lchan[i]->conn;
1772 lchan[i]->conn = NULL;
1773 conn->lchan = NULL;
Harald Welte3561bd42018-01-28 03:04:16 +01001774 osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REGULAR, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001775 }
1776
1777 fprintf(stderr, "--------------------\n");
1778
1779 printf("Test OK\n");
1780
1781 fprintf(stderr, "--------------------\n");
1782
Neels Hofmeyre3416182018-03-05 05:31:14 +01001783 talloc_free(ctx);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001784 return EXIT_SUCCESS;
1785}
1786
1787void rtp_socket_free() {}
1788void rtp_send_frame() {}
1789void rtp_socket_upstream() {}
1790void rtp_socket_create() {}
1791void rtp_socket_connect() {}
1792void rtp_socket_proxy() {}
1793void trau_mux_unmap() {}
1794void trau_mux_map_lchan() {}
1795void trau_recv_lchan() {}
1796void trau_send_frame() {}
Harald Welte3561bd42018-01-28 03:04:16 +01001797int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
1798int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
Vadim Yanitskiy6a26e2c2020-08-26 18:49:08 +07001799void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, uint8_t dlci, enum gsm0808_cause cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001800void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr) {}
Neels Hofmeyr2001dd62020-09-11 23:35:28 +00001801int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_channel)
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001802{ return 0; }
Neels Hofmeyr86ce1052020-09-18 02:49:32 +02001803int bsc_paging_start(struct bsc_paging_params *params)
1804{ return 0; }
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001805void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) {}
1806void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001807void bsc_cm_update(struct gsm_subscriber_connection *conn,
1808 const uint8_t *cm2, uint8_t cm2_len,
1809 const uint8_t *cm3, uint8_t cm3_len) {}
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001810struct gsm0808_handover_required;
1811int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell_id_list2 *target_cells)
1812{ return 0; }
1813int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, struct msgb *rr_ho_command)
1814{ return 0; }
1815int bsc_tx_bssmap_ho_detect(struct gsm_subscriber_connection *conn) { return 0; }
1816enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn,
1817 struct gsm_lchan *lchan) { return HO_RESULT_OK; }
1818void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001819void osmo_bsc_sigtran_tx_reset(void) {}
Neels Hofmeyre95b92b2020-10-09 17:18:29 +02001820void osmo_bsc_sigtran_tx_reset_ack(void) {}
Neels Hofmeyrc27ae2d2020-10-04 21:32:52 +02001821void osmo_bsc_sigtran_reset(void) {}
1822void bssmap_reset_alloc(void) {}
1823void bssmap_reset_is_conn_ready(void) {}