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