blob: 6fb145ee61a8c03675777f73f1e750fc6cec3fd6 [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 Hofmeyr909e9722017-12-07 03:54:01 +010051
Neels Hofmeyre3416182018-03-05 05:31:14 +010052void *ctx;
53
Neels Hofmeyr909e9722017-12-07 03:54:01 +010054struct gsm_network *bsc_gsmnet;
55
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020056/* override, requires '-Wl,--wrap=osmo_mgcpc_ep_ci_request'.
Harald Welte3561bd42018-01-28 03:04:16 +010057 * Catch modification of an MGCP connection. */
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020058void __real_osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020059 enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
60 struct osmo_fsm_inst *notify,
61 uint32_t event_success, uint32_t event_failure,
62 void *notify_data);
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +020063void __wrap_osmo_mgcpc_ep_ci_request(struct osmo_mgcpc_ep_ci *ci,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020064 enum mgcp_verb verb, const struct mgcp_conn_peer *verb_info,
65 struct osmo_fsm_inst *notify,
66 uint32_t event_success, uint32_t event_failure,
67 void *notify_data)
Harald Welte3561bd42018-01-28 03:04:16 +010068{
Neels Hofmeyr31f525e2018-05-14 18:14:15 +020069 struct mgcp_conn_peer fake_data = {};
70 /* All MGCP shall be successful */
71 if (!notify)
72 return;
73 osmo_fsm_inst_dispatch(notify, event_success, &fake_data);
Harald Welte3561bd42018-01-28 03:04:16 +010074}
75
Neels Hofmeyr909e9722017-12-07 03:54:01 +010076/* measurement report */
77
78uint8_t meas_rep_ba = 0, meas_rep_valid = 1, meas_valid = 1, meas_multi_rep = 0;
79uint8_t meas_dl_rxlev = 0, meas_dl_rxqual = 0;
80uint8_t meas_ul_rxlev = 0, meas_ul_rxqual = 0;
81uint8_t meas_tx_power_ms = 0, meas_tx_power_bs = 0, meas_ta_ms = 0;
82uint8_t meas_dtx_ms = 0, meas_dtx_bs = 0, meas_nr = 0;
83uint8_t meas_num_nc = 0, meas_rxlev_nc[6], meas_bsic_nc[6], meas_bcch_f_nc[6];
84
85static void gen_meas_rep(struct gsm_lchan *lchan)
86{
87 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
88 struct abis_rsl_dchan_hdr *dh;
89 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
90 uint8_t ulm[3], l1i[2], *buf;
91 struct gsm48_hdr *gh;
92 struct gsm48_meas_res *mr;
93
94 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
95 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
96 dh->c.msg_type = RSL_MT_MEAS_RES;
97 dh->ie_chan = RSL_IE_CHAN_NR;
98 dh->chan_nr = chan_nr;
99
100 msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, meas_nr++);
101
102 ulm[0] = meas_ul_rxlev | (meas_dtx_bs << 7);
103 ulm[1] = meas_ul_rxlev;
104 ulm[2] = (meas_ul_rxqual << 3) | meas_ul_rxqual;
105 msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, sizeof(ulm), ulm);
106
107 msgb_tv_put(msg, RSL_IE_BS_POWER, meas_tx_power_bs);
108
109 l1i[0] = 0;
110 l1i[1] = meas_ta_ms;
111 msgb_tv_fixed_put(msg, RSL_IE_L1_INFO, sizeof(l1i), l1i);
112
113 buf = msgb_put(msg, 3);
114 buf[0] = RSL_IE_L3_INFO;
115 buf[1] = (sizeof(*gh) + sizeof(*mr)) >> 8;
116 buf[2] = (sizeof(*gh) + sizeof(*mr)) & 0xff;
117
118 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
119 mr = (struct gsm48_meas_res *) msgb_put(msg, sizeof(*mr));
120
121 gh->proto_discr = GSM48_PDISC_RR;
122 gh->msg_type = GSM48_MT_RR_MEAS_REP;
123
124 /* measurement results */
125 mr->rxlev_full = meas_dl_rxlev;
126 mr->rxlev_sub = meas_dl_rxlev;
127 mr->rxqual_full = meas_dl_rxqual;
128 mr->rxqual_sub = meas_dl_rxqual;
129 mr->dtx_used = meas_dtx_ms;
130 mr->ba_used = meas_rep_ba;
131 mr->meas_valid = !meas_valid; /* 0 = valid */
132 if (meas_rep_valid) {
133 mr->no_nc_n_hi = meas_num_nc >> 2;
134 mr->no_nc_n_lo = meas_num_nc & 3;
135 } else {
136 /* no results for serving cells */
137 mr->no_nc_n_hi = 1;
138 mr->no_nc_n_lo = 3;
139 }
140 mr->rxlev_nc1 = meas_rxlev_nc[0];
141 mr->rxlev_nc2_hi = meas_rxlev_nc[1] >> 1;
142 mr->rxlev_nc2_lo = meas_rxlev_nc[1] & 1;
143 mr->rxlev_nc3_hi = meas_rxlev_nc[2] >> 2;
144 mr->rxlev_nc3_lo = meas_rxlev_nc[2] & 3;
145 mr->rxlev_nc4_hi = meas_rxlev_nc[3] >> 3;
146 mr->rxlev_nc4_lo = meas_rxlev_nc[3] & 7;
147 mr->rxlev_nc5_hi = meas_rxlev_nc[4] >> 4;
148 mr->rxlev_nc5_lo = meas_rxlev_nc[4] & 15;
149 mr->rxlev_nc6_hi = meas_rxlev_nc[5] >> 5;
150 mr->rxlev_nc6_lo = meas_rxlev_nc[5] & 31;
151 mr->bsic_nc1_hi = meas_bsic_nc[0] >> 3;
152 mr->bsic_nc1_lo = meas_bsic_nc[0] & 7;
153 mr->bsic_nc2_hi = meas_bsic_nc[1] >> 4;
154 mr->bsic_nc2_lo = meas_bsic_nc[1] & 15;
155 mr->bsic_nc3_hi = meas_bsic_nc[2] >> 5;
156 mr->bsic_nc3_lo = meas_bsic_nc[2] & 31;
157 mr->bsic_nc4 = meas_bsic_nc[3];
158 mr->bsic_nc5 = meas_bsic_nc[4];
159 mr->bsic_nc6 = meas_bsic_nc[5];
160 mr->bcch_f_nc1 = meas_bcch_f_nc[0];
161 mr->bcch_f_nc2 = meas_bcch_f_nc[1];
162 mr->bcch_f_nc3 = meas_bcch_f_nc[2];
163 mr->bcch_f_nc4 = meas_bcch_f_nc[3];
164 mr->bcch_f_nc5_hi = meas_bcch_f_nc[4] >> 1;
165 mr->bcch_f_nc5_lo = meas_bcch_f_nc[4] & 1;
166 mr->bcch_f_nc6_hi = meas_bcch_f_nc[5] >> 2;
167 mr->bcch_f_nc6_lo = meas_bcch_f_nc[5] & 3;
168
169 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
170 msg->l2h = (unsigned char *)dh;
171 msg->l3h = (unsigned char *)gh;
172
173 abis_rsl_rcvmsg(msg);
174}
175
176static struct gsm_bts *create_bts(int arfcn)
177{
178 struct gsm_bts *bts;
179 struct e1inp_sign_link *rsl_link;
180 int i;
181
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +0700182 bts = bsc_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_UNKNOWN, 0x3f);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100183 if (!bts) {
184 printf("No resource for bts1\n");
185 return NULL;
186 }
187
188 bts->location_area_code = 23;
189 bts->c0->arfcn = arfcn;
190
191 bts->codec.efr = 1;
192 bts->codec.hr = 1;
193 bts->codec.amr = 1;
194
Neels Hofmeyre3416182018-03-05 05:31:14 +0100195 rsl_link = talloc_zero(ctx, struct e1inp_sign_link);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100196 rsl_link->trx = bts->c0;
197 bts->c0->rsl_link = rsl_link;
198
199 bts->c0->mo.nm_state.operational = NM_OPSTATE_ENABLED;
200 bts->c0->mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200201 bts->c0->mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100202 bts->c0->bb_transc.mo.nm_state.operational = NM_OPSTATE_ENABLED;
203 bts->c0->bb_transc.mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200204 bts->c0->bb_transc.mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100205
206 /* 4 full rate and 4 half rate channels */
207 for (i = 1; i <= 6; i++) {
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200208 bts->c0->ts[i].pchan_from_config = (i < 5) ? GSM_PCHAN_TCH_F : GSM_PCHAN_TCH_H;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100209 bts->c0->ts[i].mo.nm_state.operational = NM_OPSTATE_ENABLED;
210 bts->c0->ts[i].mo.nm_state.availability = NM_AVSTATE_OK;
Pau Espin Pedrolcce0ae12020-06-22 17:57:01 +0200211 bts->c0->ts[i].mo.nm_state.administrative = NM_STATE_UNLOCKED;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200212 }
213
214 for (i = 0; i < ARRAY_SIZE(bts->c0->ts); i++) {
215 /* make sure ts->lchans[] get initialized */
Neels Hofmeyrbcdbfb72018-07-26 20:33:15 +0200216 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_RSL_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200217 osmo_fsm_inst_dispatch(bts->c0->ts[i].fi, TS_EV_OML_READY, 0);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100218 }
219 return bts;
220}
221
222void create_conn(struct gsm_lchan *lchan)
223{
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200224 static unsigned int next_imsi = 0;
225 char imsi[sizeof(lchan->conn->bsub->imsi)];
226 struct gsm_network *net = lchan->ts->trx->bts->network;
Harald Welte3561bd42018-01-28 03:04:16 +0100227 struct gsm_subscriber_connection *conn;
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200228 struct mgcp_client *fake_mgcp_client = (void*)talloc_zero(net, int);
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200229
230 conn = bsc_subscr_con_allocate(net);
Harald Welte3561bd42018-01-28 03:04:16 +0100231
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200232 conn->user_plane.mgw_endpoint = osmo_mgcpc_ep_alloc(conn->fi,
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200233 GSCON_EV_FORGET_MGW_ENDPOINT,
Neels Hofmeyrf14aaa42019-04-23 18:37:37 +0200234 fake_mgcp_client,
235 net->mgw.tdefs,
236 "test",
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200237 "fake endpoint");
Alexander Chemeris69ba8be2020-05-10 22:48:01 +0300238 conn->sccp.msc = osmo_msc_data_alloc(net, 0);
Harald Welte3561bd42018-01-28 03:04:16 +0100239
240 lchan->conn = conn;
241 conn->lchan = lchan;
Neels Hofmeyrbb6c13b2018-05-24 18:43:58 +0200242
243 /* Make up a new IMSI for this test, for logging the subscriber */
244 next_imsi ++;
245 snprintf(imsi, sizeof(imsi), "%06u", next_imsi);
246 lchan->conn->bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers, imsi);
247
Harald Welte3561bd42018-01-28 03:04:16 +0100248 /* kick the FSM from INIT through to the ACTIVE state */
249 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_REQ, NULL);
250 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_A_CONN_CFM, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100251}
252
253/* create lchan */
254struct gsm_lchan *create_lchan(struct gsm_bts *bts, int full_rate, char *codec)
255{
256 struct gsm_lchan *lchan;
257
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200258 lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100259 if (!lchan) {
260 printf("No resource for lchan\n");
261 exit(EXIT_FAILURE);
262 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200263
264 /* serious hack into osmo_fsm */
265 lchan->fi->state = LCHAN_ST_ESTABLISHED;
266 lchan->ts->fi->state = TS_ST_IN_USE;
267 LOG_LCHAN(lchan, LOGL_DEBUG, "activated by handover_test.c\n");
268
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100269 create_conn(lchan);
270 if (!strcasecmp(codec, "FR") && full_rate)
271 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
272 else if (!strcasecmp(codec, "HR") && !full_rate)
273 lchan->tch_mode = GSM48_CMODE_SPEECH_V1;
274 else if (!strcasecmp(codec, "EFR") && full_rate)
275 lchan->tch_mode = GSM48_CMODE_SPEECH_EFR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100276 else if (!strcasecmp(codec, "AMR")) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100277 lchan->tch_mode = GSM48_CMODE_SPEECH_AMR;
Philipp Maiereda6bfa2019-03-11 14:10:26 +0100278 lchan->activate.info.s15_s0 = 0x0002;
279 } else {
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100280 printf("Given codec unknown\n");
281 exit(EXIT_FAILURE);
282 }
283
284 lchan->conn->codec_list = (struct gsm0808_speech_codec_list){
285 .codec = {
286 { .fi=true, .type=GSM0808_SCT_FR1, },
287 { .fi=true, .type=GSM0808_SCT_FR2, },
288 { .fi=true, .type=GSM0808_SCT_FR3, },
289 { .fi=true, .type=GSM0808_SCT_HR1, },
290 { .fi=true, .type=GSM0808_SCT_HR3, },
291 },
292 .len = 5,
293 };
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100294
295 return lchan;
296}
297
298/* parse channel request */
299
300static int got_chan_req = 0;
301static struct gsm_lchan *chan_req_lchan = NULL;
302
303static int parse_chan_act(struct gsm_lchan *lchan, uint8_t *data)
304{
305 chan_req_lchan = lchan;
306 return 0;
307}
308
309static int parse_chan_rel(struct gsm_lchan *lchan, uint8_t *data)
310{
311 chan_req_lchan = lchan;
312 return 0;
313}
314
315/* parse handover request */
316
317static int got_ho_req = 0;
318static struct gsm_lchan *ho_req_lchan = NULL;
319
320static int parse_ho_command(struct gsm_lchan *lchan, uint8_t *data, int len)
321{
322 struct gsm48_hdr *gh = (struct gsm48_hdr *) data;
323 struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *) gh->data;
324 int arfcn;
325 struct gsm_bts *neigh;
326
327 switch (gh->msg_type) {
328 case GSM48_MT_RR_HANDO_CMD:
329 arfcn = (ho->cell_desc.arfcn_hi << 8) | ho->cell_desc.arfcn_lo;
330
331 /* look up trx. since every dummy bts uses different arfcn and
332 * only one trx, it is simple */
333 llist_for_each_entry(neigh, &bsc_gsmnet->bts_list, list) {
334 if (neigh->c0->arfcn != arfcn)
335 continue;
336 ho_req_lchan = lchan;
337 return 0;
338 }
339 break;
340 case GSM48_MT_RR_ASS_CMD:
341 ho_req_lchan = lchan;
342 return 0;
343 break;
344 default:
345 fprintf(stderr, "Error, expecting HO or AS command\n");
346 return -EINVAL;
347 }
348
349 return -1;
350}
351
352/* send channel activation ack */
353static void send_chan_act_ack(struct gsm_lchan *lchan, int act)
354{
355 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
356 struct abis_rsl_dchan_hdr *dh;
357
358 dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
359 dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
360 dh->c.msg_type = (act) ? RSL_MT_CHAN_ACTIV_ACK : RSL_MT_RF_CHAN_REL_ACK;
361 dh->ie_chan = RSL_IE_CHAN_NR;
362 dh->chan_nr = gsm_lchan2chan_nr(lchan);
363
364 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
365 msg->l2h = (unsigned char *)dh;
366
367 abis_rsl_rcvmsg(msg);
368}
369
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200370/* Send RLL Est Ind for SAPI[0] */
371static void send_est_ind(struct gsm_lchan *lchan)
372{
373 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
374 struct abis_rsl_rll_hdr *rh;
375 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
376
377 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
378 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
379 rh->c.msg_type = RSL_MT_EST_IND;
380 rh->ie_chan = RSL_IE_CHAN_NR;
381 rh->chan_nr = chan_nr;
382 rh->ie_link_id = RSL_IE_LINK_IDENT;
383 rh->link_id = 0x00;
384
385 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
386 msg->l2h = (unsigned char *)rh;
387
388 abis_rsl_rcvmsg(msg);
389}
390
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100391/* send handover complete */
392static void send_ho_complete(struct gsm_lchan *lchan, bool success)
393{
394 struct msgb *msg = msgb_alloc_headroom(256, 64, "RSL");
395 struct abis_rsl_rll_hdr *rh;
396 uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
397 uint8_t *buf;
398 struct gsm48_hdr *gh;
399 struct gsm48_ho_cpl *hc;
400
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200401 send_est_ind(lchan);
Neels Hofmeyrac85b342018-07-12 21:23:26 +0200402 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RTP_READY, 0);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +0200403
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100404 rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh));
405 rh->c.msg_discr = ABIS_RSL_MDISC_RLL;
406 rh->c.msg_type = RSL_MT_DATA_IND;
407 rh->ie_chan = RSL_IE_CHAN_NR;
408 rh->chan_nr = chan_nr;
409 rh->ie_link_id = RSL_IE_LINK_IDENT;
410 rh->link_id = 0x00;
411
412 buf = msgb_put(msg, 3);
413 buf[0] = RSL_IE_L3_INFO;
414 buf[1] = (sizeof(*gh) + sizeof(*hc)) >> 8;
415 buf[2] = (sizeof(*gh) + sizeof(*hc)) & 0xff;
416
417 gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
418 hc = (struct gsm48_ho_cpl *) msgb_put(msg, sizeof(*hc));
419
420 gh->proto_discr = GSM48_PDISC_RR;
421 gh->msg_type =
422 success ? GSM48_MT_RR_HANDO_COMPL : GSM48_MT_RR_HANDO_FAIL;
423
424 msg->dst = lchan->ts->trx->bts->c0->rsl_link;
425 msg->l2h = (unsigned char *)rh;
426 msg->l3h = (unsigned char *)gh;
427
428 abis_rsl_rcvmsg(msg);
429}
430
Neels Hofmeyr1d7473c2018-03-05 21:53:18 +0100431/* override, requires '-Wl,--wrap=abis_rsl_sendmsg'.
432 * Catch RSL messages sent towards the BTS. */
433int __real_abis_rsl_sendmsg(struct msgb *msg);
434int __wrap_abis_rsl_sendmsg(struct msgb *msg)
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100435{
436 struct abis_rsl_dchan_hdr *dh = (struct abis_rsl_dchan_hdr *) msg->data;
437 struct e1inp_sign_link *sign_link = msg->dst;
438 int rc;
439 struct gsm_lchan *lchan = rsl_lchan_lookup(sign_link->trx, dh->chan_nr, &rc);
440
441 if (rc) {
442 printf("rsl_lchan_lookup() failed\n");
443 exit(1);
444 }
445
446 switch (dh->c.msg_type) {
447 case RSL_MT_CHAN_ACTIV:
448 rc = parse_chan_act(lchan, dh->data);
449 if (rc == 0)
450 got_chan_req = 1;
451 break;
452 case RSL_MT_RF_CHAN_REL:
453 rc = parse_chan_rel(lchan, dh->data);
454 if (rc == 0)
455 send_chan_act_ack(chan_req_lchan, 0);
456 break;
457 case RSL_MT_DATA_REQ:
458 rc = parse_ho_command(lchan, msg->l3h, msgb_l3len(msg));
459 if (rc == 0)
460 got_ho_req = 1;
461 break;
462 case RSL_MT_IPAC_CRCX:
463 break;
Neels Hofmeyr5b1a7d12018-11-06 22:24:07 +0100464 case RSL_MT_DEACTIVATE_SACCH:
465 break;
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100466 default:
467 printf("unknown rsl message=0x%x\n", dh->c.msg_type);
468 }
469 return 0;
470}
471
472/* test cases */
473
474static char *test_case_0[] = {
475 "2",
476
477 "Stay in better cell\n\n"
478 "There are many neighbor cells, but only the current cell is the best\n"
479 "cell, so no handover is performed\n",
480
481 "create-bts", "7",
482 "create-ms", "0", "TCH/F", "AMR",
483 "meas-rep", "0", "30","0",
484 "6","0","20","1","21","2","18","3","20","4","23","5","19",
485 "expect-no-chan",
486 NULL
487};
488
489static char *test_case_1[] = {
490 "2",
491
492 "Handover to best better cell\n\n"
493 "The best neighbor cell is selected\n",
494
495 "create-bts", "7",
496 "create-ms", "0", "TCH/F", "AMR",
497 "meas-rep", "0", "10","0",
498 "6","0","20","1","21","2","18","3","20","4","23","5","19",
499 "expect-chan", "5", "1",
500 "ack-chan",
501 "expect-ho", "0", "1",
502 "ho-complete",
503 NULL
504};
505
506static char *test_case_2[] = {
507 "2",
508
509 "Handover and Assignment must be enabled\n\n"
510 "This test will start with disabled assignment and handover. A\n"
511 "better neighbor cell (assignment enabled) will not be selected and \n"
512 "also no assignment from TCH/H to TCH/F to improve quality. There\n"
513 "will be no handover nor assignment. After enabling assignment on the\n"
514 "current cell, the MS will assign to TCH/F. After enabling handover\n"
515 "in the current cell, but disabling in the neighbor cell, handover\n"
516 "will not be performed, until it is enabled in the neighbor cell too.\n",
517
518 "create-bts", "2",
519 "afs-rxlev-improve", "0", "5",
520 "create-ms", "0", "TCH/H", "AMR",
521 "as-enable", "0", "0",
522 "ho-enable", "0", "0",
523 "meas-rep", "0", "0","0", "1","0","30",
524 "expect-no-chan",
525 "as-enable", "0", "1",
526 "meas-rep", "0", "0","0", "1","0","30",
527 "expect-chan", "0", "1",
528 "ack-chan",
529 "expect-ho", "0", "5",
530 "ho-complete",
531 "ho-enable", "0", "1",
532 "ho-enable", "1", "0",
533 "meas-rep", "0", "0","0", "1","0","30",
534 "expect-no-chan",
535 "ho-enable", "1", "1",
536 "meas-rep", "0", "0","0", "1","0","30",
537 "expect-chan", "1", "1",
538 "ack-chan",
539 "expect-ho", "0", "1",
540 "ho-complete",
541 NULL
542};
543
544static char *test_case_3[] = {
545 "2",
546
547 "Penalty timer must not run\n\n"
548 "The MS will try to handover to a better cell, but this will fail.\n"
549 "Even though the cell is still better, handover will not be performed\n"
550 "due to penalty timer after handover failure\n",
551
552 "create-bts", "2",
553 "create-ms", "0", "TCH/F", "AMR",
554 "meas-rep", "0", "20","0", "1","0","30",
555 "expect-chan", "1", "1",
556 "ack-chan",
557 "expect-ho", "0", "1",
558 "ho-failed",
559 "meas-rep", "0", "20","0", "1","0","30",
560 "expect-no-chan",
561 NULL
562};
563
564static char *test_case_4[] = {
565 "2",
566
567 "TCH/H keeping with HR codec\n\n"
568 "The MS is using half rate V1 codec, but the better cell is congested\n"
569 "at TCH/H slots. As the congestion is removed, the handover takes\n"
570 "place.\n",
571
572 "create-bts", "2",
573 "set-min-free", "1", "TCH/H", "4",
574 "create-ms", "0", "TCH/H", "HR",
575 "meas-rep", "0", "20","0", "1","0","30",
576 "expect-no-chan",
577 "set-min-free", "1", "TCH/H", "3",
578 "meas-rep", "0", "20","0", "1","0","30",
579 "expect-chan", "1", "5",
580 "ack-chan",
581 "expect-ho", "0", "5",
582 "ho-complete",
583 NULL
584};
585
586static char *test_case_5[] = {
587 "2",
588
589 "TCH/F keeping with FR codec\n\n"
590 "The MS is using full rate V1 codec, but the better cell is congested\n"
591 "at TCH/F slots. As the congestion is removed, the handover takes\n"
592 "place.\n",
593
594 "create-bts", "2",
595 "set-min-free", "1", "TCH/F", "4",
596 "create-ms", "0", "TCH/F", "FR",
597 "meas-rep", "0", "20","0", "1","0","30",
598 "expect-no-chan",
599 "set-min-free", "1", "TCH/F", "3",
600 "meas-rep", "0", "20","0", "1","0","30",
601 "expect-chan", "1", "1",
602 "ack-chan",
603 "expect-ho", "0", "1",
604 "ho-complete",
605 NULL
606};
607
608static char *test_case_6[] = {
609 "2",
610
611 "TCH/F keeping with EFR codec\n\n"
612 "The MS is using full rate V2 codec, but the better cell is congested\n"
613 "at TCH/F slots. As the congestion is removed, the handover takes\n"
614 "place.\n",
615
616 "create-bts", "2",
617 "set-min-free", "1", "TCH/F", "4",
618 "create-ms", "0", "TCH/F", "EFR",
619 "meas-rep", "0", "20","0", "1","0","30",
620 "expect-no-chan",
621 "set-min-free", "1", "TCH/F", "3",
622 "meas-rep", "0", "20","0", "1","0","30",
623 "expect-chan", "1", "1",
624 "ack-chan",
625 "expect-ho", "0", "1",
626 "ho-complete",
627 NULL
628};
629
630static char *test_case_7[] = {
631 "2",
632
633 "TCH/F to TCH/H changing with AMR codec\n\n"
634 "The MS is using AMR V3 codec, the better cell is congested at TCH/F\n"
635 "slots. The handover is performed to non-congested TCH/H slots.\n",
636
637 "create-bts", "2",
638 "set-min-free", "1", "TCH/F", "4",
639 "create-ms", "0", "TCH/F", "AMR",
640 "meas-rep", "0", "20","0", "1","0","30",
641 "expect-chan", "1", "5",
642 "ack-chan",
643 "expect-ho", "0", "1",
644 "ho-complete",
645 NULL
646};
647
648static char *test_case_8[] = {
649 "2",
650
651 "No handover to a cell with no slots available\n\n"
652 "If no slot is available, no handover is performed\n",
653
654 "create-bts", "2",
655 "create-ms", "0", "TCH/F", "AMR",
656 "create-ms", "1", "TCH/F", "AMR",
657 "create-ms", "1", "TCH/F", "AMR",
658 "create-ms", "1", "TCH/F", "AMR",
659 "create-ms", "1", "TCH/F", "AMR",
660 "create-ms", "1", "TCH/H", "AMR",
661 "create-ms", "1", "TCH/H", "AMR",
662 "create-ms", "1", "TCH/H", "AMR",
663 "create-ms", "1", "TCH/H", "AMR",
664 "meas-rep", "0", "0","0", "1","0","30",
665 "expect-no-chan",
666 NULL
667};
668
669static char *test_case_9[] = {
670 "2",
671
672 "No more parallel handovers, if max_unsync_ho is defined\n\n"
673 "There are tree mobiles that want to handover, but only two can do\n"
674 "it at a time, because the maximum number is limited to two.\n",
675
676 "create-bts", "2",
677 "set-max-ho", "1", "2",
678 "create-ms", "0", "TCH/F", "AMR",
679 "create-ms", "0", "TCH/F", "AMR",
680 "create-ms", "0", "TCH/F", "AMR",
681 "meas-rep", "0", "0","0", "1","0","30",
682 "expect-chan", "1", "1",
683 "meas-rep", "1", "0","0", "1","0","30",
684 "expect-chan", "1", "2",
685 "meas-rep", "2", "0","0", "1","0","30",
686 "expect-no-chan",
687 NULL
688};
689
690static char *test_case_10[] = {
691 "2",
692
693 "Hysteresis\n\n"
694 "If neighbor cell is better, handover is only performed if the\n"
Martin Haukea29affd2019-11-13 22:10:41 +0100695 "amount of improvement is greater or equal hyteresis\n",
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100696
697 "create-bts", "2",
698 "create-ms", "0", "TCH/F", "AMR",
699 "meas-rep", "0", "27","0", "1","0","30",
700 "expect-no-chan",
701 "meas-rep", "0", "26","0", "1","0","30",
702 "expect-chan", "1", "1",
703 "ack-chan",
704 "expect-ho", "0", "1",
705 "ho-complete",
706 NULL
707};
708
709static char *test_case_11[] = {
710 "2",
711
712 "No Hysteresis and minimum RX level\n\n"
713 "If current cell's RX level is below mimium level, handover must be\n"
714 "performed, no matter of the hysteresis. First do not perform\n"
715 "handover to better neighbor cell, because the hysteresis is not\n"
716 "met. Second do not perform handover because better neighbor cell is\n"
717 "below minimum RX level. Third perform handover because current cell\n"
718 "is below minimum RX level, even if the better neighbor cell (minimum\n"
719 "RX level reached) does not meet the hysteresis.\n",
720
721 "create-bts", "2",
722 "create-ms", "0", "TCH/F", "AMR",
723 "meas-rep", "0", "10","0", "1","0","11",
724 "expect-no-chan",
725 "meas-rep", "0", "8","0", "1","0","9",
726 "expect-no-chan",
727 "meas-rep", "0", "9","0", "1","0","10",
728 "expect-chan", "1", "1",
729 "ack-chan",
730 "expect-ho", "0", "1",
731 "ho-complete",
732 NULL
733};
734
735static char *test_case_12[] = {
736 "2",
737
738 "No handover to congested cell\n\n"
739 "The better neighbor cell is congested, so no handover is performed.\n"
740 "After the congestion is over, handover will be performed.\n",
741
742 "create-bts", "2",
743 "create-ms", "0", "TCH/F", "AMR",
744 "set-min-free", "1", "TCH/F", "4",
745 "set-min-free", "1", "TCH/H", "4",
746 "meas-rep", "0", "20","0", "1","0","30",
747 "expect-no-chan",
748 "set-min-free", "1", "TCH/F", "3",
749 "set-min-free", "1", "TCH/H", "3",
750 "meas-rep", "0", "20","0", "1","0","30",
751 "expect-chan", "1", "1",
752 "ack-chan",
753 "expect-ho", "0", "1",
754 "ho-complete",
755 NULL
756};
757
758static char *test_case_13[] = {
759 "2",
760
761 "Handover to balance congestion\n\n"
762 "The current and the better cell are congested, so no handover is\n"
763 "performed. This is because handover would congest the neighbor cell\n"
764 "more. After congestion raises in the current cell, the handover is\n"
765 "performed to balance congestion\n",
766
767 "create-bts", "2",
768 "create-ms", "0", "TCH/F", "AMR",
769 "set-min-free", "0", "TCH/F", "4",
770 "set-min-free", "0", "TCH/H", "4",
771 "set-min-free", "1", "TCH/F", "4",
772 "set-min-free", "1", "TCH/H", "4",
773 "meas-rep", "0", "20","0", "1","0","30",
774 "expect-no-chan",
775 "create-ms", "0", "TCH/F", "AMR",
776 "meas-rep", "0", "20","0", "1","0","30",
777 "expect-chan", "1", "1",
778 "ack-chan",
779 "expect-ho", "0", "1",
780 "ho-complete",
781 NULL
782};
783
784static char *test_case_14[] = {
785 "2",
786
787 "Handover to congested cell, if RX level is below minimum\n\n"
788 "The better neighbor cell is congested, so no handover is performed.\n"
789 "If the RX level of the current cell drops below minimum acceptable\n"
790 "level, the handover is performed.\n",
791
792 "create-bts", "2",
793 "create-ms", "0", "TCH/F", "AMR",
794 "set-min-free", "1", "TCH/F", "4",
795 "set-min-free", "1", "TCH/H", "4",
796 "meas-rep", "0", "10","0", "1","0","30",
797 "expect-no-chan",
798 "meas-rep", "0", "9","0", "1","0","30",
799 "expect-chan", "1", "1",
800 "ack-chan",
801 "expect-ho", "0", "1",
802 "ho-complete",
803 NULL
804};
805
806static char *test_case_15[] = {
807 "2",
808
809 "Handover to cell with worse RXLEV, if RXQUAL is below minimum\n\n"
810 "The neighbor cell has worse RXLEV, so no handover is performed.\n"
811 "If the RXQUAL of the current cell drops below minimum acceptable\n"
812 "level, the handover is performed. It is also required that 10\n"
813 "reports are received, before RXQUAL is checked.\n",
814 /* (See also test 28, which tests for RXQUAL triggering HO to congested cell.) */
815 /* TODO: bad RXQUAL may want to prefer assignment within the same cell to avoid interference.
Martin Haukea29affd2019-11-13 22:10:41 +0100816 * See Performance Enhancements in a Frequency Hopping GSM Network (Nielsen Wigard 2002), Chapter
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100817 * 2.1.1, "Interference" in the list of triggers on p.157. */
818
819 "create-bts", "2",
820 "create-ms", "0", "TCH/F", "AMR",
821 "meas-rep", "0", "40","6", "1","0","30",
822 "expect-no-chan",
823 "meas-rep", "0", "40","6", "1","0","30",
824 "expect-no-chan",
825 "meas-rep", "0", "40","6", "1","0","30",
826 "expect-no-chan",
827 "meas-rep", "0", "40","6", "1","0","30",
828 "expect-no-chan",
829 "meas-rep", "0", "40","6", "1","0","30",
830 "expect-no-chan",
831 "meas-rep", "0", "40","6", "1","0","30",
832 "expect-no-chan",
833 "meas-rep", "0", "40","6", "1","0","30",
834 "expect-no-chan",
835 "meas-rep", "0", "40","6", "1","0","30",
836 "expect-no-chan",
837 "meas-rep", "0", "40","6", "1","0","30",
838 "expect-no-chan",
839 "meas-rep", "0", "40","6", "1","0","30",
840 "expect-chan", "1", "1",
841 "ack-chan",
842 "expect-ho", "0", "1",
843 "ho-complete",
844 NULL
845};
846
847static char *test_case_16[] = {
848 "2",
849
850 "Handover due to maximum TA exceeded\n\n"
851 "The MS in the current (best) cell has reached maximum allowed timing\n"
852 "advance. No handover is performed until the timing advance exceeds\n"
853 "it. The originating cell is still the best, but no handover is\n"
854 "performed back to that cell, because the penalty timer (due to\n"
855 "maximum allowed timing advance) is running.\n",
856
857 "create-bts", "2",
858 "create-ms", "0", "TCH/F", "AMR",
859 "set-max-ta", "0", "5", /* of cell */
860 "set-ta", "0", "5", /* of ms */
861 "meas-rep", "0", "30","0", "1","0","20",
862 "expect-no-chan",
863 "set-ta", "0", "6", /* of ms */
864 "meas-rep", "0", "30","0", "1","0","20",
865 "expect-chan", "1", "1",
866 "ack-chan",
867 "expect-ho", "0", "1",
868 "ho-complete",
869 "meas-rep", "0", "20","0", "1","0","30",
870 "expect-no-chan",
871 NULL
872};
873
874static char *test_case_17[] = {
875 "2",
876
877 "Congestion check: No congestion\n\n"
878 "Three cells have different number of used slots, but there is no\n"
879 "congestion in any of these cells. No handover is performed.\n",
880
881 "create-bts", "3",
882 "set-min-free", "0", "TCH/F", "2",
883 "set-min-free", "0", "TCH/H", "2",
884 "set-min-free", "1", "TCH/F", "2",
885 "set-min-free", "1", "TCH/H", "2",
886 "set-min-free", "2", "TCH/F", "2",
887 "set-min-free", "2", "TCH/H", "2",
888 "create-ms", "0", "TCH/F", "AMR",
889 "create-ms", "0", "TCH/F", "AMR",
890 "create-ms", "0", "TCH/H", "AMR",
891 "create-ms", "0", "TCH/H", "AMR",
892 "create-ms", "1", "TCH/F", "AMR",
893 "create-ms", "1", "TCH/H", "AMR",
894 "meas-rep", "0", "30","0", "2","0","20","1","20",
895 "expect-no-chan",
896 "meas-rep", "1", "30","0", "2","0","20","1","20",
897 "expect-no-chan",
898 "meas-rep", "2", "30","0", "2","0","20","1","20",
899 "expect-no-chan",
900 "meas-rep", "3", "30","0", "2","0","20","1","20",
901 "expect-no-chan",
902 "meas-rep", "4", "30","0", "2","0","20","1","20",
903 "expect-no-chan",
904 "meas-rep", "5", "30","0", "2","0","20","1","20",
905 "expect-no-chan",
906 "congestion-check",
907 "expect-no-chan",
908 NULL
909};
910
911static char *test_case_18[] = {
912 "2",
913
914 "Congestion check: One out of three cells is congested\n\n"
915 "Three cells have different number of used slots, but there is\n"
916 "congestion at TCH/F in the first cell. Handover is performed with\n"
917 "the best candidate.\n",
918
919 "create-bts", "3",
920 "set-min-free", "0", "TCH/F", "2",
921 "set-min-free", "0", "TCH/H", "2",
922 "set-min-free", "1", "TCH/F", "2",
923 "set-min-free", "1", "TCH/H", "2",
924 "set-min-free", "2", "TCH/F", "2",
925 "set-min-free", "2", "TCH/H", "2",
926 "create-ms", "0", "TCH/F", "AMR",
927 "create-ms", "0", "TCH/F", "AMR",
928 "create-ms", "0", "TCH/F", "AMR",
929 "create-ms", "0", "TCH/H", "AMR",
930 "create-ms", "0", "TCH/H", "AMR",
931 "create-ms", "1", "TCH/F", "AMR",
932 "create-ms", "1", "TCH/H", "AMR",
933 "meas-rep", "0", "30","0", "2","0","20","1","20",
934 "expect-no-chan",
935 "meas-rep", "1", "30","0", "2","0","20","1","20",
936 "expect-no-chan",
937 "meas-rep", "2", "30","0", "2","0","21","1","20",
938 "expect-no-chan",
939 "meas-rep", "3", "30","0", "2","0","20","1","20",
940 "expect-no-chan",
941 "meas-rep", "4", "30","0", "2","0","20","1","20",
942 "expect-no-chan",
943 "meas-rep", "5", "30","0", "2","0","20","1","20",
944 "expect-no-chan",
945 "meas-rep", "6", "30","0", "2","0","20","1","20",
946 "expect-no-chan",
947 "congestion-check",
948 "expect-chan", "1", "2",
949 "ack-chan",
950 "expect-ho", "0", "3", /* best candidate is MS 2 at BTS 1, TS 3 */
951 "ho-complete",
952 NULL
953};
954
955static char *test_case_19[] = {
956 "2",
957
958 "Congestion check: Balancing over congested cells\n\n"
Neels Hofmeyr1336d942020-08-10 21:13:55 +0200959 "Two cells are congested, but the second cell is less congested.\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +0100960 "Handover is performed to solve the congestion.\n",
961
962 "create-bts", "2",
963 "set-min-free", "0", "TCH/F", "4",
964 "set-min-free", "1", "TCH/F", "4",
965 "create-ms", "0", "TCH/F", "FR",
966 "create-ms", "0", "TCH/F", "FR",
967 "create-ms", "0", "TCH/F", "FR",
968 "create-ms", "1", "TCH/F", "FR",
969 "meas-rep", "0", "30","0", "1","0","20",
970 "expect-no-chan",
971 "meas-rep", "1", "30","0", "1","0","21",
972 "expect-no-chan",
973 "meas-rep", "2", "30","0", "1","0","20",
974 "expect-no-chan",
975 "meas-rep", "3", "30","0", "1","0","20",
976 "expect-no-chan",
977 "congestion-check",
978 "expect-chan", "1", "2",
979 "ack-chan",
980 "expect-ho", "0", "2", /* best candidate is MS 1 at BTS 0, TS 2 */
981 "ho-complete",
982 NULL
983};
984
985static char *test_case_20[] = {
986 "2",
987
988 "Congestion check: Solving congestion by handover TCH/F -> TCH/H\n\n"
989 "Two BTS, one MS in the first congested BTS must handover to\n"
990 "non-congested TCH/H of second BTS, in order to solve congestion\n",
991 "create-bts", "2",
992 "set-min-free", "0", "TCH/F", "4",
993 "set-min-free", "0", "TCH/H", "4",
994 "set-min-free", "1", "TCH/F", "4",
995 "create-ms", "0", "TCH/F", "AMR",
996 "meas-rep", "0", "30","0", "1","0","30",
997 "expect-no-chan",
998 "congestion-check",
999 "expect-chan", "1", "5",
1000 "ack-chan",
1001 "expect-ho", "0", "1",
1002 "ho-complete",
1003 NULL
1004};
1005
1006static char *test_case_21[] = {
1007 "2",
1008
1009 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1010 "Two BTS, one MS in the first congested BTS must handover to\n"
1011 "less-congested TCH/H of second BTS, in order to balance congestion\n",
1012 "create-bts", "2",
1013 "set-min-free", "0", "TCH/F", "4",
1014 "set-min-free", "0", "TCH/H", "4",
1015 "set-min-free", "1", "TCH/F", "4",
1016 "set-min-free", "1", "TCH/H", "4",
1017 "create-ms", "0", "TCH/F", "AMR",
1018 "create-ms", "0", "TCH/F", "AMR",
1019 "create-ms", "0", "TCH/H", "AMR",
1020 "meas-rep", "0", "30","0", "1","0","30",
1021 "expect-no-chan",
1022 "congestion-check",
1023 "expect-chan", "1", "1",
1024 "ack-chan",
1025 "expect-ho", "0", "1",
1026 "ho-complete",
1027 NULL
1028};
1029
1030static char *test_case_22[] = {
1031 "2",
1032
1033 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1034 "There is only one BTS. The TCH/H slots are congested. Since\n"
1035 "assignment is performed to less-congested TCH/F, the candidate with\n"
1036 "the worst RX level is chosen.\n",
1037
1038 "create-bts", "1",
1039 "set-min-free", "0", "TCH/F", "4",
1040 "set-min-free", "0", "TCH/H", "4",
1041 "create-ms", "0", "TCH/H", "AMR",
1042 "create-ms", "0", "TCH/H", "AMR",
1043 "create-ms", "0", "TCH/H", "AMR",
1044 "meas-rep", "0", "30","0", "0",
1045 "meas-rep", "1", "34","0", "0",
1046 "meas-rep", "2", "20","0", "0",
1047 "expect-no-chan",
1048 "congestion-check",
1049 "expect-chan", "0", "1",
1050 "ack-chan",
1051 "expect-ho", "0", "6",
1052 "ho-complete",
1053 NULL
1054};
1055
1056static char *test_case_23[] = {
1057 "2",
1058
1059 "Story: 'A neighbor is your friend'\n",
1060
1061 "create-bts", "3",
1062
1063 "print",
1064 "Andreas is driving along the coast, on a sunny june afternoon.\n"
1065 "Suddenly he is getting a call from his friend and neighbor Axel.\n"
1066 "\n"
1067 "What happens: Two MS are created, #0 for Axel, #1 for Andreas.",
1068 /* Axel */
1069 "create-ms", "2", "TCH/F", "AMR",
1070 /* andreas */
1071 "create-ms", "0", "TCH/F", "AMR",
1072 "meas-rep", "1", "40","0", "1","0","30",
1073 "expect-no-chan",
1074
1075 "print",
1076 "Axel asks Andreas if he would like to join them for a barbecue.\n"
1077 "Axel's house is right in the neighborhood and the weather is fine.\n"
1078 "Andreas agrees, so he drives to a close store to buy some barbecue\n"
1079 "skewers.\n"
1080 "\n"
1081 "What happens: While driving, a different cell (mounted atop the\n"
1082 "store) becomes better.",
1083 /* drive to bts 1 */
1084 "meas-rep", "1", "20","0", "1","0","35",
1085 "expect-chan", "1", "1",
1086 "ack-chan",
1087 "expect-ho", "0", "1",
1088 "ho-complete",
1089
1090 "print",
1091 "While Andreas is walking into the store, Axel asks, if he could also\n"
1092 "bring some beer. Andreas has problems understanding him: \"I have a\n"
1093 "bad reception here. The cell tower is right atop the store, but poor\n"
1094 "coverage inside. Can you repeat please?\"\n"
1095 "\n"
1096 "What happens: Inside the store the close cell is so bad, that\n"
1097 "handover back to the previous cell is required.",
1098 /* bts 1 becomes bad, so bts 0 helps out */
1099 "meas-rep", "1", "5","0", "1","0","20",
1100 "expect-chan", "0", "1",
1101 "ack-chan",
1102 "expect-ho", "1", "1",
1103 "ho-complete",
1104
1105 "print",
1106 "After Andreas bought skewers and beer, he leaves the store.\n"
1107 "\n"
1108 "What happens: Outside the store the close cell is better again, so\n"
1109 "handover back to the that cell is performed.",
1110 /* bts 1 becomes better again */
1111 "meas-rep", "1", "20","0", "1","0","35",
1112 "expect-chan", "1", "1",
1113 "ack-chan",
1114 "expect-ho", "0", "1",
1115 "ho-complete",
1116
1117 "print",
1118 /* bts 2 becomes better */
1119 "Andreas drives down to the lake where Axel's house is.\n"
1120 "\n"
1121 "What happens: There is a small cell at Axel's house, which becomes\n"
1122 "better, because the current cell has no good comverage at the lake.",
1123 "meas-rep", "1", "14","0", "2","0","2","1","63",
1124 "expect-chan", "2", "2",
1125 "ack-chan",
1126 "expect-ho", "1", "1",
1127 "ho-complete",
1128
1129 "print",
1130 "Andreas wonders why he still has good radio coverage: \"Last time it\n"
1131 "was so bad\". Axel says: \"I installed a pico cell in my house,\n"
1132 "now we can use our mobile phones down here at the lake.\"",
1133
1134 NULL
1135};
1136
1137static char *test_case_24[] = {
1138 "2",
1139 "No (or not enough) measurements for handover\n\n"
1140 "Do not solve congestion in cell, because there is no measurement.\n"
Martin Haukea29affd2019-11-13 22:10:41 +01001141 "As soon as enough measurements available (1 in our case), perform\n"
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001142 "handover. Afterwards the old cell becomes congested and the new\n"
1143 "cell is not. Do not perform handover until new measurements are\n"
1144 "received.\n",
1145
1146 /* two cells, first in congested, but no handover */
1147 "create-bts", "2",
1148 "set-min-free", "0", "TCH/F", "4",
1149 "set-min-free", "0", "TCH/H", "4",
1150 "create-ms", "0", "TCH/F", "AMR",
1151 "congestion-check",
1152 "expect-no-chan",
1153
1154 /* send measurement and trigger congestion check */
1155 "meas-rep", "0", "20","0", "1","0","20",
1156 "expect-no-chan",
1157 "congestion-check",
1158 "expect-chan", "1", "1",
1159 "ack-chan",
1160 "expect-ho", "0", "1",
1161 "ho-complete",
1162
1163 /* congest the first cell and remove congestion from second cell */
1164 "set-min-free", "0", "TCH/F", "0",
1165 "set-min-free", "0", "TCH/H", "0",
1166 "set-min-free", "1", "TCH/F", "4",
1167 "set-min-free", "1", "TCH/H", "4",
1168
1169 /* no handover until measurements applied */
1170 "congestion-check",
1171 "expect-no-chan",
1172 "meas-rep", "0", "20","0", "1","0","20",
1173 "expect-no-chan",
1174 "congestion-check",
1175 "expect-chan", "0", "1",
1176 "ack-chan",
1177 "expect-ho", "1", "1",
1178 "ho-complete",
1179 NULL
1180};
1181
1182static char *test_case_25[] = {
1183 "1",
1184
1185 "Stay in better cell\n\n"
1186 "There are many neighbor cells, but only the current cell is the best\n"
1187 "cell, so no handover is performed\n",
1188
1189 "create-bts", "7",
1190 "create-ms", "0", "TCH/F", "AMR",
1191 "meas-rep", "0", "30","0",
1192 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1193 "expect-no-chan",
1194 NULL
1195};
1196
1197static char *test_case_26[] = {
1198 "1",
1199
1200 "Handover to best better cell\n\n"
1201 "The best neighbor cell is selected\n",
1202
1203 "create-bts", "7",
1204 "create-ms", "0", "TCH/F", "AMR",
1205 "meas-rep", "0", "10","0",
1206 "6","0","20","1","21","2","18","3","20","4","23","5","19",
1207 "expect-chan", "5", "1",
1208 "ack-chan",
1209 "expect-ho", "0", "1",
1210 "ho-complete",
1211 NULL
1212};
1213
1214static char *test_case_27[] = {
1215 "2",
1216
1217 "Congestion check: Upgrading worst candidate from TCH/H -> TCH/F\n\n"
1218 "There is only one BTS. The TCH/H slots are congested. Since\n"
1219 "assignment is performed to less-congested TCH/F, the candidate with\n"
1220 "the worst RX level is chosen. (So far like test 22.)\n"
1221 "After that, trigger more congestion checks to ensure stability.\n",
1222
1223 "create-bts", "1",
1224 "set-min-free", "0", "TCH/F", "2",
1225 "set-min-free", "0", "TCH/H", "4",
1226 "create-ms", "0", "TCH/H", "AMR",
1227 "create-ms", "0", "TCH/H", "AMR",
1228 "create-ms", "0", "TCH/H", "AMR",
1229 "meas-rep", "0", "30","0", "0",
1230 "meas-rep", "1", "34","0", "0",
1231 "meas-rep", "2", "20","0", "0",
1232 "expect-no-chan",
1233 "congestion-check",
1234 "expect-chan", "0", "1",
1235 "ack-chan",
1236 "expect-ho", "0", "6",
1237 "ho-complete",
1238 "congestion-check",
1239 "expect-chan", "0", "2",
1240 "ack-chan",
1241 "expect-ho", "0", "5",
1242 "ho-complete",
1243 "congestion-check",
1244 "expect-no-chan",
1245 "congestion-check",
1246 "expect-no-chan",
1247 NULL
1248};
1249
1250static char *test_case_28[] = {
1251 "2",
1252
1253 "Handover to congested cell, if RX quality is below minimum\n\n"
1254 "The better neighbor cell is congested, so no handover is performed.\n"
1255 "If the RX quality of the current cell drops below minimum acceptable\n"
1256 "level, the handover is performed. It is also required that 10\n"
1257 "resports are received, before RX quality is checked.\n",
1258
1259 "create-bts", "2",
1260 "create-ms", "0", "TCH/F", "AMR",
1261 "set-min-free", "1", "TCH/F", "4",
1262 "set-min-free", "1", "TCH/H", "4",
1263 "meas-rep", "0", "30","6", "1","0","40",
1264 "expect-no-chan",
1265 "meas-rep", "0", "30","6", "1","0","40",
1266 "expect-no-chan",
1267 "meas-rep", "0", "30","6", "1","0","40",
1268 "expect-no-chan",
1269 "meas-rep", "0", "30","6", "1","0","40",
1270 "expect-no-chan",
1271 "meas-rep", "0", "30","6", "1","0","40",
1272 "expect-no-chan",
1273 "meas-rep", "0", "30","6", "1","0","40",
1274 "expect-no-chan",
1275 "meas-rep", "0", "30","6", "1","0","40",
1276 "expect-no-chan",
1277 "meas-rep", "0", "30","6", "1","0","40",
1278 "expect-no-chan",
1279 "meas-rep", "0", "30","6", "1","0","40",
1280 "expect-no-chan",
1281 "meas-rep", "0", "30","6", "1","0","40",
1282 "expect-chan", "1", "1",
1283 "ack-chan",
1284 "expect-ho", "0", "1",
1285 "ho-complete",
1286 NULL
1287};
1288
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001289static char *test_case_29[] = {
1290 "2",
1291
1292 "Congestion check: Balancing congestion by handover TCH/F -> TCH/H\n\n"
1293 "One BTS, and TCH/F are considered congested, TCH/H are not.\n"
1294 ,
1295 "create-bts", "1",
1296 "set-min-free", "0", "TCH/F", "3",
1297 "set-min-free", "0", "TCH/H", "0",
1298 "create-ms", "0", "TCH/F", "AMR",
1299 "create-ms", "0", "TCH/F", "AMR",
1300 "create-ms", "0", "TCH/H", "AMR",
1301 "meas-rep", "0", "30","0", "1","0","30",
1302 "expect-no-chan",
1303 "congestion-check",
1304 "expect-chan", "0", "5",
1305 "ack-chan",
1306 "expect-ho", "0", "1",
1307 "ho-complete",
1308 NULL
1309};
1310
1311
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001312static char **test_cases[] = {
1313 test_case_0,
1314 test_case_1,
1315 test_case_2,
1316 test_case_3,
1317 test_case_4,
1318 test_case_5,
1319 test_case_6,
1320 test_case_7,
1321 test_case_8,
1322 test_case_9,
1323 test_case_10,
1324 test_case_11,
1325 test_case_12,
1326 test_case_13,
1327 test_case_14,
1328 test_case_15,
1329 test_case_16,
1330 test_case_17,
1331 test_case_18,
1332 test_case_19,
1333 test_case_20,
1334 test_case_21,
1335 test_case_22,
1336 test_case_23,
1337 test_case_24,
1338 test_case_25,
1339 test_case_26,
1340 test_case_27,
1341 test_case_28,
Neels Hofmeyr7b2b4302020-08-02 02:50:17 +02001342 test_case_29,
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001343};
1344
1345static const struct log_info_cat log_categories[] = {
1346 [DHO] = {
1347 .name = "DHO",
1348 .description = "Hand-Over Process",
1349 .color = "\033[1;38m",
1350 .enabled = 1, .loglevel = LOGL_DEBUG,
1351 },
1352 [DHODEC] = {
1353 .name = "DHODEC",
1354 .description = "Hand-Over Decision",
1355 .color = "\033[1;38m",
1356 .enabled = 1, .loglevel = LOGL_DEBUG,
1357 },
1358 [DMEAS] = {
1359 .name = "DMEAS",
1360 .description = "Radio Measurement Processing",
1361 .enabled = 1, .loglevel = LOGL_DEBUG,
1362 },
1363 [DREF] = {
1364 .name = "DREF",
1365 .description = "Reference Counting",
1366 .enabled = 1, .loglevel = LOGL_DEBUG,
1367 },
1368 [DRSL] = {
1369 .name = "DRSL",
Keithd925c7c2018-04-16 13:40:07 +02001370 .description = "A-bis Radio Signalling Link (RSL)",
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001371 .color = "\033[1;35m",
1372 .enabled = 1, .loglevel = LOGL_DEBUG,
1373 },
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001374 [DRR] = {
1375 .name = "DRR",
1376 .description = "RR",
1377 .color = "\033[1;35m",
1378 .enabled = 1, .loglevel = LOGL_DEBUG,
1379 },
1380 [DRLL] = {
1381 .name = "DRLL",
1382 .description = "RLL",
1383 .color = "\033[1;35m",
1384 .enabled = 1, .loglevel = LOGL_DEBUG,
1385 },
Harald Welte3561bd42018-01-28 03:04:16 +01001386 [DMSC] = {
1387 .name = "DMSC",
1388 .description = "Mobile Switching Center",
1389 .enabled = 1, .loglevel = LOGL_DEBUG,
1390 },
Neels Hofmeyr3c5612f2018-07-11 19:53:39 +02001391 [DCHAN] = {
1392 .name = "DCHAN",
1393 .description = "lchan FSM",
1394 .color = "\033[1;32m",
1395 .enabled = 1, .loglevel = LOGL_DEBUG,
1396 },
1397 [DTS] = {
1398 .name = "DTS",
1399 .description = "timeslot FSM",
1400 .color = "\033[1;31m",
1401 .enabled = 1, .loglevel = LOGL_DEBUG,
1402 },
1403 [DAS] = {
1404 .name = "DAS",
1405 .description = "assignment FSM",
1406 .color = "\033[1;33m",
1407 .enabled = 1, .loglevel = LOGL_DEBUG,
1408 },
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001409};
1410
1411const struct log_info log_info = {
1412 .cat = log_categories,
1413 .num_cat = ARRAY_SIZE(log_categories),
1414};
1415
1416int main(int argc, char **argv)
1417{
1418 char **test_case;
1419 struct gsm_bts *bts[256];
1420 int bts_num = 0;
1421 struct gsm_lchan *lchan[256];
1422 int lchan_num = 0;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001423 int i;
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001424 int algorithm;
Neels Hofmeyr00727552018-02-21 14:33:15 +01001425 int test_case_i;
1426 int last_test_i;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001427
Neels Hofmeyre3416182018-03-05 05:31:14 +01001428 ctx = talloc_named_const(NULL, 0, "handover_test");
1429 msgb_talloc_ctx_init(ctx, 0);
1430
Neels Hofmeyr00727552018-02-21 14:33:15 +01001431 test_case_i = argc > 1? atoi(argv[1]) : -1;
1432 last_test_i = ARRAY_SIZE(test_cases) - 1;
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001433
Neels Hofmeyr00727552018-02-21 14:33:15 +01001434 if (test_case_i < 0 || test_case_i > last_test_i) {
1435 for (i = 0; i <= last_test_i; i++) {
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001436 printf("Test #%d (algorithm %s):\n%s\n", i,
1437 test_cases[i][0], test_cases[i][1]);
1438 }
Neels Hofmeyr00727552018-02-21 14:33:15 +01001439 printf("\nPlease specify test case number 0..%d\n", last_test_i);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001440 return EXIT_FAILURE;
1441 }
1442
Neels Hofmeyre3416182018-03-05 05:31:14 +01001443 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001444
1445 log_set_print_category(osmo_stderr_target, 1);
1446 log_set_print_category_hex(osmo_stderr_target, 0);
1447 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001448 osmo_fsm_log_addr(false);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001449
Neels Hofmeyr958f2592018-05-27 01:26:31 +02001450 bsc_network_alloc();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001451 if (!bsc_gsmnet)
1452 exit(1);
1453
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001454 ts_fsm_init();
1455 lchan_fsm_init();
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001456 bsc_subscr_conn_fsm_init();
1457 handover_fsm_init();
1458
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001459 ho_set_algorithm(bsc_gsmnet->ho, 2);
1460 ho_set_ho_active(bsc_gsmnet->ho, true);
1461 ho_set_hodec2_as_active(bsc_gsmnet->ho, true);
1462 ho_set_hodec2_min_rxlev(bsc_gsmnet->ho, -100);
1463 ho_set_hodec2_rxlev_avg_win(bsc_gsmnet->ho, 1);
1464 ho_set_hodec2_rxlev_neigh_avg_win(bsc_gsmnet->ho, 1);
1465 ho_set_hodec2_rxqual_avg_win(bsc_gsmnet->ho, 10);
1466 ho_set_hodec2_pwr_hysteresis(bsc_gsmnet->ho, 3);
1467 ho_set_hodec2_pwr_interval(bsc_gsmnet->ho, 1);
1468 ho_set_hodec2_afs_bias_rxlev(bsc_gsmnet->ho, 0);
1469 ho_set_hodec2_min_rxqual(bsc_gsmnet->ho, 5);
1470 ho_set_hodec2_afs_bias_rxqual(bsc_gsmnet->ho, 0);
1471 ho_set_hodec2_max_distance(bsc_gsmnet->ho, 9999);
1472 ho_set_hodec2_ho_max(bsc_gsmnet->ho, 9999);
1473 ho_set_hodec2_penalty_max_dist(bsc_gsmnet->ho, 300);
1474 ho_set_hodec2_penalty_failed_ho(bsc_gsmnet->ho, 60);
1475 ho_set_hodec2_penalty_failed_as(bsc_gsmnet->ho, 60);
1476
Vadim Yanitskiy4f3a6412020-05-31 01:56:20 +07001477 /* We don't really need any specific model here */
1478 bts_model_unknown_init();
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001479
Neels Hofmeyr00727552018-02-21 14:33:15 +01001480 test_case = test_cases[test_case_i];
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001481
1482 fprintf(stderr, "--------------------\n");
1483 fprintf(stderr, "Performing the following test %d (algorithm %s):\n%s",
Neels Hofmeyr00727552018-02-21 14:33:15 +01001484 test_case_i, test_case[0], test_case[1]);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001485 algorithm = atoi(test_case[0]);
1486 test_case += 2;
1487 fprintf(stderr, "--------------------\n");
1488
1489 /* Disable the congestion check timer, we will trigger manually. */
1490 bsc_gsmnet->hodec2.congestion_check_interval_s = 0;
1491
1492 handover_decision_1_init();
1493 hodec2_init(bsc_gsmnet);
1494
1495 while (*test_case) {
1496 if (!strcmp(*test_case, "create-bts")) {
1497 static int arfcn = 870;
1498 int n = atoi(test_case[1]);
1499 fprintf(stderr, "- Creating %d BTS (one TRX each, "
1500 "TS(1-4) are TCH/F, TS(5-6) are TCH/H)\n", n);
1501 for (i = 0; i < n; i++)
1502 bts[bts_num + i] = create_bts(arfcn++);
Neels Hofmeyr00727552018-02-21 14:33:15 +01001503 for (i = 0; i < n; i++) {
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001504 if (gsm_generate_si(bts[bts_num + i], SYSINFO_TYPE_2) <= 0)
Neels Hofmeyr00727552018-02-21 14:33:15 +01001505 fprintf(stderr, "Error generating SI2\n");
1506 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001507 bts_num += n;
1508 test_case += 2;
1509 } else
1510 if (!strcmp(*test_case, "as-enable")) {
1511 fprintf(stderr, "- Set assignment enable state at "
1512 "BTS %s to %s\n", test_case[1], test_case[2]);
1513 ho_set_hodec2_as_active(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1514 test_case += 3;
1515 } else
1516 if (!strcmp(*test_case, "ho-enable")) {
1517 fprintf(stderr, "- Set handover enable state at "
1518 "BTS %s to %s\n", test_case[1], test_case[2]);
1519 ho_set_ho_active(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1520 test_case += 3;
1521 } else
1522 if (!strcmp(*test_case, "afs-rxlev-improve")) {
1523 fprintf(stderr, "- Set afs RX level improvement at "
1524 "BTS %s to %s\n", test_case[1], test_case[2]);
1525 ho_set_hodec2_afs_bias_rxlev(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1526 test_case += 3;
1527 } else
1528 if (!strcmp(*test_case, "afs-rxqual-improve")) {
1529 fprintf(stderr, "- Set afs RX quality improvement at "
1530 "BTS %s to %s\n", test_case[1], test_case[2]);
1531 ho_set_hodec2_afs_bias_rxqual(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1532 test_case += 3;
1533 } else
1534 if (!strcmp(*test_case, "set-min-free")) {
1535 fprintf(stderr, "- Setting minimum required free %s "
1536 "slots at BTS %s to %s\n", test_case[2],
1537 test_case[1], test_case[3]);
1538 if (!strcmp(test_case[2], "TCH/F"))
1539 ho_set_hodec2_tchf_min_slots(bts[atoi(test_case[1])]->ho, atoi(test_case[3]));
1540 else
1541 ho_set_hodec2_tchh_min_slots(bts[atoi(test_case[1])]->ho, atoi(test_case[3]));
1542 test_case += 4;
1543 } else
1544 if (!strcmp(*test_case, "set-max-ho")) {
1545 fprintf(stderr, "- Setting maximum parallel handovers "
1546 "at BTS %s to %s\n", test_case[1],
1547 test_case[2]);
1548 ho_set_hodec2_ho_max( bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1549 test_case += 3;
1550 } else
1551 if (!strcmp(*test_case, "set-max-ta")) {
1552 fprintf(stderr, "- Setting maximum timing advance "
1553 "at BTS %s to %s\n", test_case[1],
1554 test_case[2]);
1555 ho_set_hodec2_max_distance(bts[atoi(test_case[1])]->ho, atoi(test_case[2]));
1556 test_case += 3;
1557 } else
1558 if (!strcmp(*test_case, "create-ms")) {
1559 fprintf(stderr, "- Creating mobile #%d at BTS %s on "
1560 "%s with %s codec\n", lchan_num, test_case[1],
1561 test_case[2], test_case[3]);
1562 lchan[lchan_num] = create_lchan(bts[atoi(test_case[1])],
1563 !strcmp(test_case[2], "TCH/F"), test_case[3]);
1564 if (!lchan[lchan_num]) {
1565 printf("Failed to create lchan!\n");
1566 return EXIT_FAILURE;
1567 }
1568 fprintf(stderr, " * New MS is at BTS %d TS %d\n",
1569 lchan[lchan_num]->ts->trx->bts->nr,
1570 lchan[lchan_num]->ts->nr);
1571 lchan_num++;
1572 test_case += 4;
1573 } else
1574 if (!strcmp(*test_case, "set-ta")) {
1575 fprintf(stderr, "- Setting maximum timing advance "
1576 "at MS %s to %s\n", test_case[1],
1577 test_case[2]);
1578 meas_ta_ms = atoi(test_case[2]);
1579 test_case += 3;
1580 } else
1581 if (!strcmp(*test_case, "meas-rep")) {
1582 /* meas-rep <lchan-nr> <rxlev> <rxqual> <nr-of-neighbors> [<cell-idx> <rxlev> [...]] */
1583 int n = atoi(test_case[4]);
1584 struct gsm_lchan *lc = lchan[atoi(test_case[1])];
1585 fprintf(stderr, "- Sending measurement report from "
1586 "mobile #%s (rxlev=%s, rxqual=%s)\n",
1587 test_case[1], test_case[2], test_case[3]);
1588 meas_dl_rxlev = atoi(test_case[2]);
1589 meas_dl_rxqual = atoi(test_case[3]);
1590 meas_num_nc = n;
1591 test_case += 5;
1592 for (i = 0; i < n; i++) {
1593 int nr = atoi(test_case[0]);
1594 /* since our bts is not in the list of neighbor
1595 * cells, we need to shift */
1596 if (nr >= lc->ts->trx->bts->nr)
1597 nr++;
1598 fprintf(stderr, " * Neighbor cell #%s, actual "
1599 "BTS %d (rxlev=%s)\n", test_case[0], nr,
1600 test_case[1]);
1601 meas_bcch_f_nc[i] = atoi(test_case[0]);
1602 /* bts number, not counting our own */
1603 meas_rxlev_nc[i] = atoi(test_case[1]);
1604 meas_bsic_nc[i] = 0x3f;
1605 test_case += 2;
1606 }
1607 got_chan_req = 0;
1608 gen_meas_rep(lc);
1609 } else
1610 if (!strcmp(*test_case, "congestion-check")) {
1611 fprintf(stderr, "- Triggering congestion check\n");
1612 got_chan_req = 0;
1613 if (algorithm == 2)
1614 hodec2_congestion_check(bsc_gsmnet);
1615 test_case += 1;
1616 } else
1617 if (!strcmp(*test_case, "expect-chan")) {
1618 fprintf(stderr, "- Expecting channel request at BTS %s "
1619 "TS %s\n", test_case[1], test_case[2]);
1620 if (!got_chan_req) {
1621 printf("Test failed, because no channel was "
1622 "requested\n");
1623 return EXIT_FAILURE;
1624 }
1625 fprintf(stderr, " * Got channel request at BTS %d "
1626 "TS %d\n", chan_req_lchan->ts->trx->bts->nr,
1627 chan_req_lchan->ts->nr);
1628 if (chan_req_lchan->ts->trx->bts->nr
1629 != atoi(test_case[1])) {
1630 printf("Test failed, because channel was not "
1631 "requested on expected BTS\n");
1632 return EXIT_FAILURE;
1633 }
1634 if (chan_req_lchan->ts->nr != atoi(test_case[2])) {
1635 printf("Test failed, because channel was not "
1636 "requested on expected TS\n");
1637 return EXIT_FAILURE;
1638 }
1639 test_case += 3;
1640 } else
1641 if (!strcmp(*test_case, "expect-no-chan")) {
1642 fprintf(stderr, "- Expecting no channel request\n");
1643 if (got_chan_req) {
1644 fprintf(stderr, " * Got channel request at "
1645 "BTS %d TS %d\n",
1646 chan_req_lchan->ts->trx->bts->nr,
1647 chan_req_lchan->ts->nr);
1648 printf("Test failed, because channel was "
1649 "requested\n");
1650 return EXIT_FAILURE;
1651 }
1652 fprintf(stderr, " * Got no channel request\n");
1653 test_case += 1;
1654 } else
1655 if (!strcmp(*test_case, "expect-ho")) {
1656 fprintf(stderr, "- Expecting handover/assignment "
1657 "request at BTS %s TS %s\n", test_case[1],
1658 test_case[2]);
1659 if (!got_ho_req) {
1660 printf("Test failed, because no handover was "
1661 "requested\n");
1662 return EXIT_FAILURE;
1663 }
1664 fprintf(stderr, " * Got handover/assignment request at "
1665 "BTS %d TS %d\n",
1666 ho_req_lchan->ts->trx->bts->nr,
1667 ho_req_lchan->ts->nr);
1668 if (ho_req_lchan->ts->trx->bts->nr
1669 != atoi(test_case[1])) {
1670 printf("Test failed, because "
1671 "handover/assignment was not commanded "
1672 "at the expected BTS\n");
1673 return EXIT_FAILURE;
1674 }
1675 if (ho_req_lchan->ts->nr != atoi(test_case[2])) {
1676 printf("Test failed, because "
1677 "handover/assignment was not commanded "
1678 "at the expected TS\n");
1679 return EXIT_FAILURE;
1680 }
1681 test_case += 3;
1682 } else
1683 if (!strcmp(*test_case, "ack-chan")) {
1684 fprintf(stderr, "- Acknowledging channel request\n");
1685 if (!got_chan_req) {
1686 printf("Cannot ack channel, because no "
1687 "request\n");
1688 return EXIT_FAILURE;
1689 }
1690 test_case += 1;
1691 got_ho_req = 0;
1692 send_chan_act_ack(chan_req_lchan, 1);
1693 } else
1694 if (!strcmp(*test_case, "ho-complete")) {
1695 fprintf(stderr, "- Acknowledging handover/assignment "
1696 "request\n");
1697 if (!got_chan_req) {
1698 printf("Cannot ack handover/assignment, "
1699 "because no chan request\n");
1700 return EXIT_FAILURE;
1701 }
1702 if (!got_ho_req) {
1703 printf("Cannot ack handover/assignment, "
1704 "because no ho request\n");
1705 return EXIT_FAILURE;
1706 }
1707 test_case += 1;
1708 got_chan_req = 0;
1709 got_ho_req = 0;
1710 /* switch lchan */
1711 for (i = 0; i < lchan_num; i++) {
1712 if (lchan[i] == ho_req_lchan) {
1713 fprintf(stderr, " * MS %d changes from "
1714 "BTS=%d TS=%d to BTS=%d "
1715 "TS=%d\n", i,
1716 lchan[i]->ts->trx->bts->nr,
1717 lchan[i]->ts->nr,
1718 chan_req_lchan->ts->trx->bts->nr,
1719 chan_req_lchan->ts->nr);
1720 lchan[i] = chan_req_lchan;
1721 }
1722 }
1723 send_ho_complete(chan_req_lchan, true);
1724 } else
1725 if (!strcmp(*test_case, "ho-failed")) {
1726 fprintf(stderr, "- Making handover fail\n");
1727 if (!got_chan_req) {
1728 printf("Cannot fail handover, because no chan "
1729 "request\n");
1730 return EXIT_FAILURE;
1731 }
1732 test_case += 1;
1733 got_chan_req = 0;
1734 got_ho_req = 0;
1735 send_ho_complete(ho_req_lchan, false);
1736 } else
1737 if (!strcmp(*test_case, "print")) {
1738 fprintf(stderr, "\n%s\n\n", test_case[1]);
1739 test_case += 2;
1740 } else {
1741 printf("Unknown test command '%s', please fix!\n",
1742 *test_case);
1743 return EXIT_FAILURE;
1744 }
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001745
1746 {
1747 /* Help the lchan out of releasing states */
1748 struct gsm_bts *bts;
1749 llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
1750 struct gsm_bts_trx *trx;
1751 llist_for_each_entry(trx, &bts->trx_list, list) {
1752 int ts_nr;
1753 for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
1754 struct gsm_lchan *lchan;
1755 ts_for_each_lchan(lchan, &trx->ts[ts_nr]) {
1756
1757 if (lchan->fi && lchan->fi->state == LCHAN_ST_WAIT_BEFORE_RF_RELEASE) {
1758 osmo_fsm_inst_state_chg(lchan->fi, LCHAN_ST_WAIT_RF_RELEASE_ACK, 0, 0);
1759 osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_RSL_RF_CHAN_REL_ACK, 0);
1760 }
1761 }
1762 }
1763 }
1764 }
1765 }
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001766 }
1767
1768 for (i = 0; i < lchan_num; i++) {
1769 struct gsm_subscriber_connection *conn = lchan[i]->conn;
1770 lchan[i]->conn = NULL;
1771 conn->lchan = NULL;
Harald Welte3561bd42018-01-28 03:04:16 +01001772 osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_REGULAR, NULL);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001773 }
1774
1775 fprintf(stderr, "--------------------\n");
1776
1777 printf("Test OK\n");
1778
1779 fprintf(stderr, "--------------------\n");
1780
Neels Hofmeyre3416182018-03-05 05:31:14 +01001781 talloc_free(ctx);
Neels Hofmeyr909e9722017-12-07 03:54:01 +01001782 return EXIT_SUCCESS;
1783}
1784
1785void rtp_socket_free() {}
1786void rtp_send_frame() {}
1787void rtp_socket_upstream() {}
1788void rtp_socket_create() {}
1789void rtp_socket_connect() {}
1790void rtp_socket_proxy() {}
1791void trau_mux_unmap() {}
1792void trau_mux_map_lchan() {}
1793void trau_recv_lchan() {}
1794void trau_send_frame() {}
Harald Welte3561bd42018-01-28 03:04:16 +01001795int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
1796int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg) { return 0; }
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001797void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) {}
1798void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr) {}
1799int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, uint16_t chosen_channel)
1800{ return 0; }
1801void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) {}
1802void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause) {}
Neels Hofmeyrc19581f2018-05-27 03:05:18 +02001803void bsc_cm_update(struct gsm_subscriber_connection *conn,
1804 const uint8_t *cm2, uint8_t cm2_len,
1805 const uint8_t *cm3, uint8_t cm3_len) {}
Neels Hofmeyr31f525e2018-05-14 18:14:15 +02001806struct gsm0808_handover_required;
1807int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell_id_list2 *target_cells)
1808{ return 0; }
1809int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, struct msgb *rr_ho_command)
1810{ return 0; }
1811int bsc_tx_bssmap_ho_detect(struct gsm_subscriber_connection *conn) { return 0; }
1812enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection *conn,
1813 struct gsm_lchan *lchan) { return HO_RESULT_OK; }
1814void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn) {}