blob: 73547ad9da664faa364161eb7c04adccfd24c6dc [file] [log] [blame]
Philipp Maier844876f2018-07-13 09:17:07 +02001/*
2 * (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * All Rights Reserved
4 *
5 * Author: Philipp Maier
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <osmocom/bsc/osmo_bsc.h>
23#include <osmocom/bsc/bsc_msc_data.h>
24#include <osmocom/bsc/gsm_04_80.h>
25#include <osmocom/core/application.h>
26#include <osmocom/bsc/codec_pref.h>
27
28#include <stdio.h>
29
30void *ctx = NULL;
31
32#define MSC_AUDIO_SUPPORT_MAX 5
33#define N_CONFIG_VARIANTS 9
34
35/* Make sure that there is some memory to put our test configuration. */
36static void init_msc_config(struct bsc_msc_data *msc)
37{
38 unsigned int i;
39
40 msc->audio_support = talloc_zero_array(ctx, struct gsm_audio_support *, MSC_AUDIO_SUPPORT_MAX);
41 msc->audio_length = MSC_AUDIO_SUPPORT_MAX;
42 for (i = 0; i < MSC_AUDIO_SUPPORT_MAX; i++) {
43 msc->audio_support[i] = talloc_zero(msc->audio_support, struct gsm_audio_support);
44 }
45}
46
47/* Free memory that we have used for the test configuration. */
48static void free_msc_config(struct bsc_msc_data *msc)
49{
50 talloc_free(msc->audio_support);
51}
52
53/* The speech codec list is sent by the MS and lists the voice codec settings
54 * that the MS is able to support. The BSC must select one of this codecs
55 * depending on what the MSC is able to support. The following function
56 * generates some realistically made up speech codec lists. */
57static void make_scl_config(struct gsm0808_speech_codec_list *scl, uint8_t config_no)
58{
59 OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
60
61 switch (config_no) {
62 case 0:
63 /* FR1 only */
64 scl->codec[0].type = GSM0808_SCT_FR1;
65 scl->len = 1;
66 break;
67 case 1:
68 /* HR1 only */
69 scl->codec[0].type = GSM0808_SCT_HR1;
70 scl->len = 1;
71 break;
72 case 2:
73 /* FR2 only */
74 scl->codec[0].type = GSM0808_SCT_FR2;
75 scl->len = 1;
76 break;
77 case 3:
78 /* FR3 only */
79 scl->codec[0].type = GSM0808_SCT_FR3;
80 scl->len = 1;
81 break;
82 case 4:
83 /* HR3 only */
84 scl->codec[0].type = GSM0808_SCT_HR3;
85 scl->len = 1;
86 break;
87 case 5:
88 /* FR1 and HR1 */
89 scl->codec[0].type = GSM0808_SCT_FR1;
90 scl->codec[1].type = GSM0808_SCT_HR1;
91 scl->len = 2;
92 break;
93 case 6:
94 /* FR1, FR2 and HR1 */
95 scl->codec[0].type = GSM0808_SCT_FR1;
96 scl->codec[1].type = GSM0808_SCT_FR2;
97 scl->codec[2].type = GSM0808_SCT_HR1;
98 scl->len = 3;
99 break;
100 case 7:
101 /* FR1, FR3 and HR3 */
102 scl->codec[0].type = GSM0808_SCT_FR1;
103 scl->codec[1].type = GSM0808_SCT_FR3;
104 scl->codec[2].type = GSM0808_SCT_HR3;
105 scl->len = 3;
106 break;
107 case 8:
108 /* FR1, FR2, FR3, HR1 and HR3 */
109 scl->codec[0].type = GSM0808_SCT_FR1;
110 scl->codec[1].type = GSM0808_SCT_FR2;
111 scl->codec[2].type = GSM0808_SCT_FR3;
112 scl->codec[3].type = GSM0808_SCT_HR1;
113 scl->codec[4].type = GSM0808_SCT_HR3;
114 scl->len = 5;
115 break;
116 }
117}
118
119/* The channel type element which is sent to the BSC by the MSC lists all the
120 * codecs that the MSC is able to support. The following function generates
121 * a realistic permitted speech settings */
122static void make_ct_config(struct gsm0808_channel_type *ct, uint8_t config_no)
123{
124 OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
125
126 switch (config_no) {
127 case 0:
128 /* FR1 only */
129 ct->perm_spch[0] = GSM0808_PERM_FR1;
130 ct->perm_spch_len = 1;
131 break;
132 case 1:
133 /* HR1 only */
134 ct->perm_spch[0] = GSM0808_PERM_HR1;
135 ct->perm_spch_len = 1;
136 break;
137 case 2:
138 /* FR2 only */
139 ct->perm_spch[0] = GSM0808_PERM_FR2;
140 ct->perm_spch_len = 1;
141 break;
142 case 3:
143 /* FR3 only */
144 ct->perm_spch[0] = GSM0808_PERM_FR3;
145 ct->perm_spch_len = 1;
146 break;
147 case 4:
148 /* HR3 only */
149 ct->perm_spch[0] = GSM0808_PERM_HR3;
150 ct->perm_spch_len = 1;
151 break;
152 case 5:
153 /* FR1 and HR1 */
154 ct->perm_spch[0] = GSM0808_PERM_FR1;
155 ct->perm_spch[1] = GSM0808_PERM_HR1;
156 ct->perm_spch_len = 2;
157 break;
158 case 6:
159 /* FR1, FR2 and HR1 */
160 ct->perm_spch[0] = GSM0808_PERM_FR1;
161 ct->perm_spch[1] = GSM0808_PERM_FR2;
162 ct->perm_spch[2] = GSM0808_PERM_HR1;
163 ct->perm_spch_len = 3;
164 break;
165 case 7:
166 /* FR1, FR3 and HR3 */
167 ct->perm_spch[0] = GSM0808_PERM_FR1;
168 ct->perm_spch[1] = GSM0808_PERM_FR3;
169 ct->perm_spch[2] = GSM0808_PERM_HR3;
170 ct->perm_spch_len = 3;
171 break;
172 case 8:
173 /* FR1, FR2, FR3, HR1 and HR3 */
174 ct->perm_spch[0] = GSM0808_PERM_FR1;
175 ct->perm_spch[1] = GSM0808_PERM_FR2;
176 ct->perm_spch[2] = GSM0808_PERM_FR3;
177 ct->perm_spch[3] = GSM0808_PERM_HR1;
178 ct->perm_spch[4] = GSM0808_PERM_HR3;
179 ct->perm_spch_len = 5;
180 break;
181 }
182}
183
184/* Generate some realistic MSC configuration which one also could find in the
185 * real world. This configuration acts as a filter. While the MSC could in
186 * theory advertise codecs more codecs as we are able to support we have to
187 * make sure that only the codecs we have support for are considered. */
188static void make_msc_config(struct bsc_msc_data *msc, uint8_t config_no)
189{
190 /* 1 = FR1/HR1
191 * 2 = FR2/HR2
192 * 3 = FR2/HR3
193 * Note: HR2 is deprecated */
194
195 OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
196
197 switch (config_no) {
198 case 0:
199 /* FR1 only */
200 msc->audio_support[0]->ver = 1;
201 msc->audio_support[0]->hr = 0;
202 msc->audio_length = 1;
203 break;
204 case 1:
205 /* HR1 only */
206 msc->audio_support[0]->ver = 1;
207 msc->audio_support[0]->hr = 1;
208 msc->audio_length = 1;
209 break;
210 case 2:
211 /* FR2 only */
212 msc->audio_support[0]->ver = 2;
213 msc->audio_support[0]->hr = 0;
214 msc->audio_length = 1;
215 break;
216 case 3:
217 /* FR3 only */
218 msc->audio_support[0]->ver = 3;
219 msc->audio_support[0]->hr = 0;
220 msc->audio_length = 1;
221 break;
222 case 4:
223 /* HR3 only */
224 msc->audio_support[0]->ver = 3;
225 msc->audio_support[0]->hr = 1;
226 msc->audio_length = 1;
227 break;
228 case 5:
229 /* FR1 and HR1 */
230 msc->audio_support[0]->ver = 1;
231 msc->audio_support[0]->hr = 0;
232 msc->audio_support[1]->ver = 1;
233 msc->audio_support[1]->hr = 1;
234 msc->audio_length = 2;
235 break;
236 case 6:
237 /* FR1, FR2 and HR1 */
238 msc->audio_support[0]->ver = 1;
239 msc->audio_support[0]->hr = 0;
240 msc->audio_support[1]->ver = 2;
241 msc->audio_support[1]->hr = 0;
242 msc->audio_support[2]->ver = 1;
243 msc->audio_support[2]->hr = 1;
244 msc->audio_length = 3;
245 break;
246 case 7:
247 /* FR1, FR3 and HR3 */
248 msc->audio_support[0]->ver = 1;
249 msc->audio_support[0]->hr = 0;
250 msc->audio_support[1]->ver = 3;
251 msc->audio_support[1]->hr = 0;
252 msc->audio_support[2]->ver = 3;
253 msc->audio_support[2]->hr = 1;
254 msc->audio_length = 3;
255 break;
256 case 8:
257 /* FR1, FR2, FR3, HR1 and HR3 */
258 msc->audio_support[0]->ver = 1;
259 msc->audio_support[0]->hr = 0;
260 msc->audio_support[1]->ver = 2;
261 msc->audio_support[1]->hr = 0;
262 msc->audio_support[2]->ver = 3;
263 msc->audio_support[2]->hr = 0;
264 msc->audio_support[3]->ver = 1;
265 msc->audio_support[3]->hr = 1;
266 msc->audio_support[4]->ver = 3;
267 msc->audio_support[4]->hr = 1;
268 msc->audio_length = 5;
269 break;
270 }
271}
272
273/* Try execute match_codec_pref(), display input and output parameters */
274static int test_match_codec_pref(const struct gsm0808_channel_type *ct,
275 const struct gsm0808_speech_codec_list *scl, const struct bsc_msc_data *msc)
276{
277 int rc;
278 unsigned int i;
279 int full_rate;
280 enum gsm48_chan_mode chan_mode;
281
282 printf("Determining channel mode and rate:\n");
283
284 printf(" * MS: speech codec list (%u items):\n", scl->len);
285 for (i = 0; i < scl->len; i++)
286 printf(" codec[%u]->type=%s\n", i, gsm0808_speech_codec_type_name(scl->codec[i].type));
287
288 printf(" * MSC: channel type permitted speech (%u items):\n", ct->perm_spch_len);
289 for (i = 0; i < ct->perm_spch_len; i++)
290 printf(" perm_spch[%u]=%s\n", i, gsm0808_permitted_speech_name(ct->perm_spch[i]));
291
292 printf(" * BSS: audio support settings (%u items):\n", msc->audio_length);
293 for (i = 0; i < msc->audio_length; i++)
294 if (msc->audio_support[i]->hr)
295 printf(" audio_support[%u]=HR%u\n", i, msc->audio_support[i]->ver);
296 else
297 printf(" audio_support[%u]=FR%u\n", i, msc->audio_support[i]->ver);
298
299 rc = match_codec_pref(&full_rate, &chan_mode, ct, scl, msc);
300 printf(" * result: rc=%i, full_rate=%i, chan_mode=%s\n", rc, full_rate, gsm48_chan_mode_name(chan_mode));
301
302 printf("\n");
303
304 return rc;
305}
306
307/* MS, MSC and local MSC settings are the same */
308static void test_one_to_one(void)
309{
310 unsigned int i;
311 struct gsm0808_channel_type ct_msc;
312 struct gsm0808_speech_codec_list scl_ms;
313 struct bsc_msc_data msc_local;
314 int rc;
315
316 printf("============== test_one_to_one ==============\n\n");
317
318 init_msc_config(&msc_local);
319
320 for (i = 0; i < N_CONFIG_VARIANTS; i++) {
321 make_msc_config(&msc_local, i);
322 make_scl_config(&scl_ms, i);
323 make_ct_config(&ct_msc, i);
324 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
325 OSMO_ASSERT(rc == 0);
326 }
327
328 free_msc_config(&msc_local);
329}
330
331/* Network supports all combinations, MS varies */
332static void test_ms(void)
333{
334 unsigned int i;
335 struct gsm0808_channel_type ct_msc;
336 struct gsm0808_speech_codec_list scl_ms;
337 struct bsc_msc_data msc_local;
338 int rc;
339
340 printf("============== test_ms ==============\n\n");
341
342 init_msc_config(&msc_local);
343
344 make_msc_config(&msc_local, 8);
345 make_ct_config(&ct_msc, 8);
346 for (i = 0; i < N_CONFIG_VARIANTS; i++) {
347 make_scl_config(&scl_ms, i);
348 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
349 OSMO_ASSERT(rc == 0);
350 }
351
352 free_msc_config(&msc_local);
353}
354
355/* BSS and MS support all combinations, MSC varies */
356static void test_ct(void)
357{
358 unsigned int i;
359 struct gsm0808_channel_type ct_msc;
360 struct gsm0808_speech_codec_list scl_ms;
361 struct bsc_msc_data msc_local;
362 int rc;
363
364 printf("============== test_ct ==============\n\n");
365
366 init_msc_config(&msc_local);
367
368 make_msc_config(&msc_local, 8);
369 make_scl_config(&scl_ms, 8);
370 for (i = 0; i < N_CONFIG_VARIANTS; i++) {
371 make_ct_config(&ct_msc, i);
372 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
373 OSMO_ASSERT(rc == 0);
374 }
375
376 free_msc_config(&msc_local);
377}
378
379/* MSC and MS support all combinations, BSS varies */
380static void test_msc(void)
381{
382 unsigned int i;
383 struct gsm0808_channel_type ct_msc;
384 struct gsm0808_speech_codec_list scl_ms;
385 struct bsc_msc_data msc_local;
386 int rc;
387
388 printf("============== test_msc ==============\n\n");
389
390 init_msc_config(&msc_local);
391
392 make_ct_config(&ct_msc, 8);
393 make_scl_config(&scl_ms, 8);
394 for (i = 0; i < N_CONFIG_VARIANTS; i++) {
395 make_msc_config(&msc_local, 8);
396 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
397 OSMO_ASSERT(rc == 0);
398 }
399
400 free_msc_config(&msc_local);
401}
402
403/* Some mixed configurations that are supposed to work */
404static void test_selected_working(void)
405{
406 struct gsm0808_channel_type ct_msc;
407 struct gsm0808_speech_codec_list scl_ms;
408 struct bsc_msc_data msc_local;
409 int rc;
410
411 printf("============== test_selected_working ==============\n\n");
412
413 init_msc_config(&msc_local);
414
415 make_scl_config(&scl_ms, 6);
416 make_ct_config(&ct_msc, 5);
417 make_msc_config(&msc_local, 7);
418 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
419 OSMO_ASSERT(rc == 0);
420
421 make_scl_config(&scl_ms, 0);
422 make_ct_config(&ct_msc, 5);
423 make_msc_config(&msc_local, 7);
424 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
425 OSMO_ASSERT(rc == 0);
426
427 make_scl_config(&scl_ms, 1);
428 make_ct_config(&ct_msc, 5);
429 make_msc_config(&msc_local, 6);
430 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
431 OSMO_ASSERT(rc == 0);
432
433 free_msc_config(&msc_local);
434}
435
436/* Some mixed configurations that can not work */
437static void test_selected_non_working(void)
438{
439 struct gsm0808_channel_type ct_msc;
440 struct gsm0808_speech_codec_list scl_ms;
441 struct bsc_msc_data msc_local;
442 int rc;
443
444 printf("============== test_selected_non_working ==============\n\n");
445
446 init_msc_config(&msc_local);
447
448 make_scl_config(&scl_ms, 1);
449 make_ct_config(&ct_msc, 5);
450 make_msc_config(&msc_local, 7);
451 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
452 OSMO_ASSERT(rc == -1);
453
454 make_scl_config(&scl_ms, 1);
455 make_ct_config(&ct_msc, 5);
456 make_msc_config(&msc_local, 7);
457 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
458 OSMO_ASSERT(rc == -1);
459
460 make_scl_config(&scl_ms, 1);
461 make_ct_config(&ct_msc, 4);
462 make_msc_config(&msc_local, 6);
463 rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
464 OSMO_ASSERT(rc == -1);
465
466 free_msc_config(&msc_local);
467}
468
469static const struct log_info_cat log_categories[] = {
470 [DMSC] = {
471 .name = "DMSC",
472 .description = "Mobile Switching Center",
473 .enabled = 1,.loglevel = LOGL_NOTICE,
474 },
475};
476
477static const struct log_info log_info = {
478 .cat = log_categories,
479 .num_cat = ARRAY_SIZE(log_categories),
480};
481
482int main(int argc, char **argv)
483{
484 ctx = talloc_named_const(NULL, 0, "codec_pref_test");
485 msgb_talloc_ctx_init(ctx, 0);
486 osmo_init_logging2(ctx, &log_info);
487
488 test_one_to_one();
489 test_ms();
490 test_ct();
491 test_msc();
492 test_selected_working();
493 test_selected_non_working();
494
495 printf("Testing execution completed.\n");
496 talloc_free(ctx);
497 return 0;
498}