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