blob: 8a89357c182e0c6e64e1a8b4a496dc714695ee3d [file] [log] [blame]
Harald Weltec8a0b932012-08-24 21:27:26 +02001/*
2 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
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 General Public License as published by
7 * the Free Software Foundation; either version 2 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 *
Harald Weltec8a0b932012-08-24 21:27:26 +020015 */
16
Neels Hofmeyr30856ca2020-06-16 13:17:20 +020017#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
18
Harald Weltec8a0b932012-08-24 21:27:26 +020019#include <string.h>
20#include <stdio.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020021#include <stdlib.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020022
23#include <osmocom/gsm/protocol/gsm_04_08.h>
24#include <osmocom/gsm/gsm48_ie.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020025#include <osmocom/gsm/gsm48.h>
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +020026#include <osmocom/gsm/gsm48_arfcn_range_encode.h>
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +010027#include <osmocom/gsm/gsm_utils.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020028#include <osmocom/gsm/mncc.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020029#include <osmocom/core/backtrace.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020030#include <osmocom/core/utils.h>
31#include <osmocom/core/msgb.h>
32
33
Manawyrm714843a2023-10-14 16:57:12 +020034static const uint8_t csd_9600_v110_lv[] = { 0x07, 0xa1, 0x88, 0x89, 0x21, 0x15, 0x63, 0x80 };
Harald Weltec8a0b932012-08-24 21:27:26 +020035
36static const struct gsm_mncc_bearer_cap bcap_csd_9600_v110 = {
Vadim Yanitskiybfb11d82024-01-19 01:55:36 +070037 .transfer = GSM48_BCAP_ITCAP_UNR_DIG_INF,
38 .mode = GSM48_BCAP_TMOD_CIRCUIT,
39 .coding = GSM48_BCAP_CODING_GSM_STD,
40 .radio = GSM48_BCAP_RRQ_FR_ONLY,
41 .speech_ver[0] = -1,
Harald Weltec8a0b932012-08-24 21:27:26 +020042 .data = {
Vadim Yanitskiybfb11d82024-01-19 01:55:36 +070043 .rate_adaption = GSM48_BCAP_RA_V110_X30,
44 .sig_access = GSM48_BCAP_SA_I440_I450,
45 .async = 1,
46 .nr_stop_bits = 1,
47 .nr_data_bits = 8,
48 .user_rate = GSM48_BCAP_UR_9600,
49 .parity = GSM48_BCAP_PAR_NONE,
50 .interm_rate = GSM48_BCAP_IR_16k,
51 .transp = GSM48_BCAP_TR_TRANSP,
52 .modem_type = GSM48_BCAP_MT_NONE,
Harald Weltec8a0b932012-08-24 21:27:26 +020053 },
54};
55
Vadim Yanitskiydefda4c2024-01-19 00:55:27 +070056static const uint8_t csd_4800_rlp_lv[] = { 0x07, 0xa1, 0x88, 0x89, 0x21, 0x14, 0x63, 0xa0 };
57
58static const struct gsm_mncc_bearer_cap bcap_csd_4800_rlp = {
59 .transfer = GSM48_BCAP_ITCAP_UNR_DIG_INF,
60 .mode = GSM48_BCAP_TMOD_CIRCUIT,
61 .coding = GSM48_BCAP_CODING_GSM_STD,
62 .radio = GSM48_BCAP_RRQ_FR_ONLY,
63 .speech_ver[0] = -1,
64 .data = {
65 .rate_adaption = GSM48_BCAP_RA_V110_X30,
66 .sig_access = GSM48_BCAP_SA_I440_I450,
67 .async = 1,
68 .nr_stop_bits = 1,
69 .nr_data_bits = 8,
70 .user_rate = GSM48_BCAP_UR_4800,
71 .parity = GSM48_BCAP_PAR_NONE,
72 .interm_rate = GSM48_BCAP_IR_16k,
73 .transp = GSM48_BCAP_TR_RLP,
74 .modem_type = GSM48_BCAP_MT_NONE,
75 },
76};
77
78static const uint8_t csd_2400_v22bis_lv[] = { 0x07, 0xa2, 0xb8, 0x81, 0x21, 0x13, 0x43, 0x83 };
79
80static const struct gsm_mncc_bearer_cap bcap_csd_2400_v22bis = {
81 .transfer = GSM48_BCAP_ITCAP_3k1_AUDIO,
82 .mode = GSM48_BCAP_TMOD_CIRCUIT,
83 .coding = GSM48_BCAP_CODING_GSM_STD,
84 .radio = GSM48_BCAP_RRQ_FR_ONLY,
85 .speech_ver[0] = -1,
86 .data = {
87 .rate_adaption = GSM48_BCAP_RA_NONE,
88 .sig_access = GSM48_BCAP_SA_I440_I450,
89 .async = 1,
90 .nr_stop_bits = 1,
91 .nr_data_bits = 8,
92 .user_rate = GSM48_BCAP_UR_2400,
93 .parity = GSM48_BCAP_PAR_NONE,
94 .interm_rate = GSM48_BCAP_IR_8k,
95 .transp = GSM48_BCAP_TR_TRANSP,
96 .modem_type = GSM48_BCAP_MT_V22bis,
97 },
98};
99
Harald Weltec8a0b932012-08-24 21:27:26 +0200100static const uint8_t speech_all_lv[] = { 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81 };
101
102static const struct gsm_mncc_bearer_cap bcap_speech_all = {
Vadim Yanitskiybfb11d82024-01-19 01:55:36 +0700103 .transfer = GSM48_BCAP_ITCAP_SPEECH,
104 .mode = GSM48_BCAP_TMOD_CIRCUIT,
105 .coding = GSM48_BCAP_CODING_GSM_STD,
106 .radio = GSM48_BCAP_RRQ_DUAL_FR,
Harald Weltec8a0b932012-08-24 21:27:26 +0200107 .speech_ver = {
108 4, 2, 0, 5, 1, -1,
109 },
110};
111
Vadim Yanitskiy95fc8ea2022-07-03 05:41:02 +0700112static const uint8_t speech_no3a_lv[] = { 0x01, 0xa0 };
113
114static const struct gsm_mncc_bearer_cap bcap_speech_no3a = {
Vadim Yanitskiybfb11d82024-01-19 01:55:36 +0700115 .transfer = GSM48_BCAP_ITCAP_SPEECH,
116 .mode = GSM48_BCAP_TMOD_CIRCUIT,
117 .coding = GSM48_BCAP_CODING_GSM_STD,
118 .radio = GSM48_BCAP_RRQ_FR_ONLY,
Vadim Yanitskiy95fc8ea2022-07-03 05:41:02 +0700119 .speech_ver = {
120 0, -1,
121 },
122};
123
Harald Weltec8a0b932012-08-24 21:27:26 +0200124
125struct bcap_test {
126 const uint8_t *lv;
127 const struct gsm_mncc_bearer_cap *bc;
128 const char *name;
129};
130
131static const struct bcap_test bcap_tests[] = {
132 { csd_9600_v110_lv, &bcap_csd_9600_v110, "CSD 9600/V.110/transparent" },
Vadim Yanitskiydefda4c2024-01-19 00:55:27 +0700133 { csd_4800_rlp_lv, &bcap_csd_4800_rlp, "CSD 4800/RLP/non-transparent" },
134 { /* XXX: this testcase is expected to fail because octet 4 is not represented in
135 * 'struct gsm_mncc_bearer_cap' and the encoder unconditionally hard-codes it to 0x88. */
136 csd_2400_v22bis_lv, &bcap_csd_2400_v22bis, "CSD 2400/V.22bis/transparent" },
Harald Weltec8a0b932012-08-24 21:27:26 +0200137 { speech_all_lv, &bcap_speech_all, "Speech, all codecs" },
Vadim Yanitskiy95fc8ea2022-07-03 05:41:02 +0700138 { speech_no3a_lv, &bcap_speech_no3a, "Speech, without octet 3a" },
Harald Weltec8a0b932012-08-24 21:27:26 +0200139};
140
Harald Weltee61d4592022-11-03 11:05:58 +0100141static int test_bearer_cap(void)
Harald Weltec8a0b932012-08-24 21:27:26 +0200142{
143 struct gsm_mncc_bearer_cap bc;
144 int i, rc;
145
146 for (i = 0; i < ARRAY_SIZE(bcap_tests); i++) {
147 struct msgb *msg = msgb_alloc(100, "test");
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700148 bool pass = false;
Harald Weltec8a0b932012-08-24 21:27:26 +0200149 int lv_len;
150
151 memset(&bc, 0, sizeof(bc));
152
153 /* test decoding */
154 rc = gsm48_decode_bearer_cap(&bc, bcap_tests[i].lv);
155 if (rc < 0) {
156 fprintf(stderr, "Error decoding %s\n",
157 bcap_tests[i].name);
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700158 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200159 }
160 if (memcmp(&bc, bcap_tests[i].bc, sizeof(bc))) {
161 fprintf(stderr, "Incorrect decoded result of %s:\n",
162 bcap_tests[i].name);
163 fprintf(stderr, " should: %s\n",
164 osmo_hexdump((uint8_t *) bcap_tests[i].bc, sizeof(bc)));
165 fprintf(stderr, " is: %s\n",
166 osmo_hexdump((uint8_t *) &bc, sizeof(bc)));
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700167 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200168 }
169
170 /* also test re-encode? */
171 rc = gsm48_encode_bearer_cap(msg, 1, &bc);
172 if (rc < 0) {
173 fprintf(stderr, "Error encoding %s\n",
174 bcap_tests[i].name);
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700175 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200176 }
177 lv_len = bcap_tests[i].lv[0]+1;
178 if (memcmp(msg->data, bcap_tests[i].lv, lv_len)) {
179 fprintf(stderr, "Incorrect encoded result of %s:\n",
180 bcap_tests[i].name);
181 fprintf(stderr, " should: %s\n",
182 osmo_hexdump(bcap_tests[i].lv, lv_len));
183 fprintf(stderr, " is: %s\n",
184 osmo_hexdump(msg->data, msg->len));
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700185 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200186 }
187
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700188 /* all checks passed */
189 pass = true;
190
191verdict:
192 printf("Test `%s' %sed\n", bcap_tests[i].name, pass ? "pass" : "fail");
Harald Weltec8a0b932012-08-24 21:27:26 +0200193 msgb_free(msg);
194 }
195
196 return 0;
197}
198
Max99377c22017-08-30 19:17:50 +0200199static inline void dump_ra(const struct gprs_ra_id *raid)
200{
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100201 printf("%s%s\n", osmo_rai_name(raid), raid->mnc_3_digits ? " (3-digit MNC)" : "");
Max99377c22017-08-30 19:17:50 +0200202}
203
204static inline void check_ra(const struct gprs_ra_id *raid)
205{
Maxf1ad60e2018-01-05 14:19:33 +0100206 struct gsm48_ra_id ra;
Max99377c22017-08-30 19:17:50 +0200207 struct gprs_ra_id raid0 = {
208 .mnc = 0,
209 .mcc = 0,
210 .lac = 0,
211 .rac = 0,
212 };
213
Maxf1ad60e2018-01-05 14:19:33 +0100214 gsm48_encode_ra(&ra, raid);
215 printf("Constructed RA:\n");
Max99377c22017-08-30 19:17:50 +0200216
Maxf1ad60e2018-01-05 14:19:33 +0100217 gsm48_parse_ra(&raid0, (const uint8_t *)&ra);
Max99377c22017-08-30 19:17:50 +0200218 dump_ra(raid);
Neels Hofmeyrc38b32d2018-02-20 15:13:18 +0100219 printf("MCC+MNC in BCD: %s\n", osmo_hexdump(ra.digits, sizeof(ra.digits)));
Max99377c22017-08-30 19:17:50 +0200220 dump_ra(&raid0);
221 printf("RA test...");
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100222 if (raid->mnc != raid0.mnc || raid->mcc != raid0.mcc || raid->lac != raid0.lac || raid->rac != raid0.rac
223 || (raid->mnc_3_digits || raid->mnc > 99) != raid0.mnc_3_digits)
Max99377c22017-08-30 19:17:50 +0200224 printf("FAIL\n");
225 else
226 printf("passed\n");
227}
228
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100229static inline void check_lai(const struct gprs_ra_id *raid)
230{
231 int rc;
232 struct gsm48_loc_area_id lai = {};
233 struct gprs_ra_id decoded = {};
234 struct gprs_ra_id _laid = *raid;
235 struct gprs_ra_id *laid = &_laid;
236 laid->rac = 0;
237
238 printf("- gsm48_generate_lai() from "); dump_ra(laid);
239
240 gsm48_generate_lai(&lai, laid->mcc, laid->mnc, laid->lac);
241 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
242 rc = gsm48_decode_lai(&lai, &decoded.mcc, &decoded.mnc, &decoded.lac);
243 if (rc) {
244 printf(" gsm48_decode_lai() returned %d --> FAIL\n", rc);
245 return;
246 }
247 printf(" gsm48_decode_lai() gives "); dump_ra(&decoded);
248 if (decoded.mcc == laid->mcc
249 && decoded.mnc == laid->mnc
250 && decoded.lac == laid->lac)
251 printf(" passed\n");
252 else
253 printf(" FAIL\n");
254}
255
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100256static inline void dump_lai(const struct osmo_location_area_id *lai)
257{
258 printf("%s%s\n", osmo_lai_name(lai), lai->plmn.mnc_3_digits ? " (3-digit MNC)" : "");
259}
260
261static inline void check_lai2(const struct gprs_ra_id *raid)
262{
263 struct gsm48_loc_area_id lai = {};
264 struct osmo_location_area_id decoded = {};
265 struct osmo_location_area_id laid = {
266 .plmn = {
267 .mcc = raid->mcc,
268 .mnc = raid->mnc,
269 .mnc_3_digits = raid->mnc_3_digits,
270 },
271 .lac = raid->lac,
272 };
273
274 printf("- gsm48_generate_lai2() from "); dump_lai(&laid);
275
276 gsm48_generate_lai2(&lai, &laid);
277 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
278 gsm48_decode_lai2(&lai, &decoded);
279 printf(" gsm48_decode_lai2() gives "); dump_lai(&decoded);
280 if (decoded.plmn.mcc == laid.plmn.mcc
281 && decoded.plmn.mnc == laid.plmn.mnc
282 && decoded.lac == laid.lac
283 && decoded.plmn.mnc_3_digits == (laid.plmn.mnc_3_digits || laid.plmn.mnc > 99))
284 printf(" passed\n");
285 else
286 printf(" FAIL\n");
287}
288
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100289static struct gprs_ra_id test_ra_cap_items[] = {
290 {
Max99377c22017-08-30 19:17:50 +0200291 .mcc = 77,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100292 .mnc = 121,
Max99377c22017-08-30 19:17:50 +0200293 .lac = 666,
294 .rac = 5,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100295 },
296 {
Max99377c22017-08-30 19:17:50 +0200297 .mcc = 84,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100298 .mnc = 98,
Max99377c22017-08-30 19:17:50 +0200299 .lac = 11,
300 .rac = 89,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100301 },
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100302 {
303 .mcc = 0,
304 .mnc = 0,
305 .lac = 0,
306 .rac = 0,
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100307 .mnc_3_digits = false,
308 /* expecting 000-00, BCD = 00 f0 00 */
309 },
310 {
311 .mcc = 0,
312 .mnc = 0,
313 .lac = 0,
314 .rac = 0,
315 .mnc_3_digits = true,
316 /* expecting 000-000, BCD = 00 00 00 */
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100317 },
318 {
319 .mcc = 999,
320 .mnc = 999,
321 .lac = 65535,
322 .rac = 255,
323 },
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100324 {
325 .mcc = 1,
326 .mnc = 2,
327 .lac = 23,
328 .rac = 42,
329 .mnc_3_digits = false,
330 /* expecting 001-02, BCD = 00 f1 20 */
331 },
332 {
333 .mcc = 1,
334 .mnc = 2,
335 .lac = 23,
336 .rac = 42,
337 .mnc_3_digits = true,
338 /* expecting 001-002, BCD = 00 21 00 */
339 },
340 {
341 .mcc = 12,
342 .mnc = 34,
343 .lac = 56,
344 .rac = 78,
345 .mnc_3_digits = false,
346 /* expecting 012-34, BCD = 10 f2 43 */
347 },
348 {
349 .mcc = 12,
350 .mnc = 34,
351 .lac = 23,
352 .rac = 42,
353 .mnc_3_digits = true,
354 /* expecting 012-034, BCD = 10 42 30 */
355 },
356 {
357 .mcc = 123,
358 .mnc = 456,
359 .lac = 23,
360 .rac = 42,
361 .mnc_3_digits = false,
362 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
363 },
364 {
365 .mcc = 123,
366 .mnc = 456,
367 .lac = 23,
368 .rac = 42,
369 .mnc_3_digits = true,
370 /* expecting 123-456, BCD = 21 63 54 (same) */
371 },
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100372};
Max99377c22017-08-30 19:17:50 +0200373
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100374static void test_ra_cap(void)
375{
376 int i;
377
378 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++)
379 check_ra(&test_ra_cap_items[i]);
Max99377c22017-08-30 19:17:50 +0200380}
381
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100382static void test_lai_encode_decode(void)
383{
384 int i;
385
386 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++) {
387 check_lai(&test_ra_cap_items[i]);
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100388 check_lai2(&test_ra_cap_items[i]);
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100389 }
390}
391
Neels Hofmeyr8d423942023-06-08 00:35:41 +0200392static struct osmo_routing_area_id test_osmo_routing_area_id_items[] = {
393 {
394 .lac = {
395 .plmn = {
396 .mcc = 77,
397 .mnc = 121,
398 },
399 .lac = 666,
400 },
401 .rac = 5,
402 },
403 {
404 .lac = {
405 .plmn = {
406 .mcc = 84,
407 .mnc = 98,
408 },
409 .lac = 11,
410 },
411 .rac = 89,
412 },
413 {
414 .lac = {
415 .plmn = {
416 .mcc = 0,
417 .mnc = 0,
418 .mnc_3_digits = false,
419 /* expecting 000-00, BCD = 00 f0 00 */
420 },
421 .lac = 0,
422 },
423 .rac = 0,
424 },
425 {
426 .lac = {
427 .plmn = {
428 .mcc = 0,
429 .mnc = 0,
430 .mnc_3_digits = true,
431 /* expecting 000-000, BCD = 00 00 00 */
432 },
433 .lac = 0,
434 },
435 .rac = 0,
436 },
437 {
438 .lac = {
439 .plmn = {
440 .mcc = 999,
441 .mnc = 999,
442 },
443 .lac = 65535,
444 },
445 .rac = 255,
446 },
447 {
448 .lac = {
449 .plmn = {
450 .mcc = 1,
451 .mnc = 2,
452 .mnc_3_digits = false,
453 /* expecting 001-02, BCD = 00 f1 20 */
454 },
455 .lac = 23,
456 },
457 .rac = 42,
458 },
459 {
460 .lac = {
461 .plmn = {
462 .mcc = 1,
463 .mnc = 2,
464 .mnc_3_digits = true,
465 /* expecting 001-002, BCD = 00 21 00 */
466 },
467 .lac = 23,
468 },
469 .rac = 42,
470 },
471 {
472 .lac = {
473 .plmn = {
474 .mcc = 12,
475 .mnc = 34,
476 .mnc_3_digits = false,
477 /* expecting 012-34, BCD = 10 f2 43 */
478 },
479 .lac = 56,
480 },
481 .rac = 78,
482 },
483 {
484 .lac = {
485 .plmn = {
486 .mcc = 12,
487 .mnc = 34,
488 .mnc_3_digits = true,
489 /* expecting 012-034, BCD = 10 42 30 */
490 },
491 .lac = 23,
492 },
493 .rac = 42,
494 },
495 {
496 .lac = {
497 .plmn = {
498 .mcc = 123,
499 .mnc = 456,
500 .mnc_3_digits = false,
501 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
502 },
503 .lac = 23,
504 },
505 .rac = 42,
506 },
507 {
508 .lac = {
509 .plmn = {
510 .mcc = 123,
511 .mnc = 456,
512 .mnc_3_digits = true,
513 /* expecting 123-456, BCD = 21 63 54 (same) */
514 },
515 .lac = 23,
516 },
517 .rac = 42,
518 },
519};
520
521static inline void dump_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
522{
523 printf("%s%s", osmo_rai_name2(raid), raid->lac.plmn.mnc_3_digits ? " (3-digit MNC)" : "");
524}
525
526static inline void check_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
527{
528 uint8_t buf[sizeof(struct gsm48_ra_id)] = {};
529 struct osmo_routing_area_id raid0 = {};
530 int rc;
531
532 printf("RA ID: ");
533 dump_osmo_routing_area_id(raid);
534
535 rc = osmo_routing_area_id_encode_buf(buf, sizeof(buf), raid);
536 printf("osmo_routing_area_id_encode_buf(): %src=%d\n", osmo_hexdump(buf, sizeof(buf)), rc);
537
538 rc = osmo_routing_area_id_decode(&raid0, buf, sizeof(buf));
539 printf("osmo_routing_area_id_decode(): ");
540 dump_osmo_routing_area_id(&raid0);
541 printf(" rc=%d\n", rc);
542
543 if (osmo_rai_cmp(raid, &raid0))
544 printf("FAIL\n");
545 else
546 printf("ok\n");
547}
548
549static void test_osmo_routing_area_id(void)
550{
551 int i;
552 printf("==%s()==\n", __func__);
553 for (i = 0; i < ARRAY_SIZE(test_osmo_routing_area_id_items); i++)
554 check_osmo_routing_area_id(&test_osmo_routing_area_id_items[i]);
555}
556
Philipp Maiere36be562020-11-12 11:33:54 +0100557static void dump_cm3(struct gsm48_classmark3 *cm3)
558{
559 printf("mult_band_supp=%02x\n", cm3->mult_band_supp);
560 printf("a5_bits=%02x\n", cm3->a5_bits);
561 printf("assoc_radio_cap_1=%02x\n", cm3->assoc_radio_cap_1);
562 printf("assoc_radio_cap_2=%02x\n", cm3->assoc_radio_cap_2);
563 printf("\n");
564 printf("r_support.present=%u\n", cm3->r_support.present);
565 printf("r_support.r_gsm_assoc_radio_cap=%02x\n",
566 cm3->r_support.r_gsm_assoc_radio_cap);
567 printf("\n");
568 printf("hscsd_mult_slot_cap.present=%u\n",
569 cm3->hscsd_mult_slot_cap.present);
570 printf("hscsd_mult_slot_cap.mslot_class=%02x\n",
571 cm3->hscsd_mult_slot_cap.mslot_class);
572 printf("\n");
573 printf("ucs2_treatment=%u\n", cm3->ucs2_treatment);
574 printf("extended_meas_cap=%u\n", cm3->extended_meas_cap);
575 printf("\n");
576 printf("ms_meas_cap.present=%u\n", cm3->ms_meas_cap.present);
577 printf("ms_meas_cap.sms_value=%02x\n", cm3->ms_meas_cap.sms_value);
578 printf("ms_meas_cap.sm_value=%02x\n", cm3->ms_meas_cap.sm_value);
579 printf("\n");
580 printf("ms_pos_method_cap.present=%u\n",
581 cm3->ms_pos_method_cap.present);
582 printf("ms_pos_method_cap.method=%02x\n",
583 cm3->ms_pos_method_cap.method);
584 printf("\n");
585 printf("ecsd_multislot_cap.present=%u\n",
586 cm3->ecsd_multislot_cap.present);
587 printf("ecsd_multislot_cap.mslot_class=%02x\n",
588 cm3->ecsd_multislot_cap.mslot_class);
589 printf("\n");
590 printf("psk8_struct.present=%u\n", cm3->psk8_struct.present);
591 printf("psk8_struct.mod_cap=%u\n", cm3->psk8_struct.mod_cap);
592 printf("psk8_struct.rf_pwr_cap_1.present=%u\n",
593 cm3->psk8_struct.rf_pwr_cap_1.present);
594 printf("psk8_struct.rf_pwr_cap_1.value=%02x\n",
595 cm3->psk8_struct.rf_pwr_cap_1.value);
596 printf("psk8_struct.rf_pwr_cap_2.present=%u\n",
597 cm3->psk8_struct.rf_pwr_cap_2.present);
598 printf("psk8_struct.rf_pwr_cap_2.value=%02x\n",
599 cm3->psk8_struct.rf_pwr_cap_2.value);
600 printf("\n");
601 printf("gsm_400_bands_supp.present=%u\n",
602 cm3->gsm_400_bands_supp.present);
603 printf("gsm_400_bands_supp.value=%02x\n",
604 cm3->gsm_400_bands_supp.value);
605 printf("gsm_400_bands_supp.assoc_radio_cap=%02x\n",
606 cm3->gsm_400_bands_supp.assoc_radio_cap);
607 printf("\n");
608 printf("gsm_850_assoc_radio_cap.present=%u\n",
609 cm3->gsm_850_assoc_radio_cap.present);
610 printf("gsm_850_assoc_radio_cap.value=%02x\n",
611 cm3->gsm_850_assoc_radio_cap.value);
612 printf("\n");
613 printf("gsm_1900_assoc_radio_cap.present=%u\n",
614 cm3->gsm_1900_assoc_radio_cap.present);
615 printf("gsm_1900_assoc_radio_cap.value=%02x\n",
616 cm3->gsm_1900_assoc_radio_cap.value);
617 printf("\n");
618 printf("umts_fdd_rat_cap=%u\n", cm3->umts_fdd_rat_cap);
619 printf("umts_tdd_rat_cap=%u\n", cm3->umts_tdd_rat_cap);
620 printf("cdma200_rat_cap=%u\n", cm3->cdma200_rat_cap);
621 printf("\n");
622 printf("dtm_gprs_multislot_cap.present=%u\n",
623 cm3->dtm_gprs_multislot_cap.present);
624 printf("dtm_gprs_multislot_cap.mslot_class=%02x\n",
625 cm3->dtm_gprs_multislot_cap.mslot_class);
626 printf("dtm_gprs_multislot_cap.single_slot_dtm=%u\n",
627 cm3->dtm_gprs_multislot_cap.single_slot_dtm);
628 printf("dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present=%u\n",
629 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present);
630 printf("dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class=%02x\n",
631 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class);
632 printf("\n");
633 printf("single_band_supp.present=%u\n", cm3->single_band_supp.present);
634 printf("single_band_supp.value=%u\n", cm3->single_band_supp.value);
635 printf("\n");
636 printf("gsm_750_assoc_radio_cap.present=%u\n",
637 cm3->gsm_750_assoc_radio_cap.present);
638 printf("gsm_750_assoc_radio_cap.value=%02x\n",
639 cm3->gsm_750_assoc_radio_cap.value);
640 printf("\n");
641 printf("umts_1_28_mcps_tdd_rat_cap=%u\n",
642 cm3->umts_1_28_mcps_tdd_rat_cap);
643 printf("geran_feature_package=%u\n", cm3->geran_feature_package);
644 printf("\n");
645 printf("extended_dtm_gprs_multislot_cap.present=%u\n",
646 cm3->extended_dtm_gprs_multislot_cap.present);
647 printf("extended_dtm_gprs_multislot_cap.mslot_class=%02x\n",
648 cm3->extended_dtm_gprs_multislot_cap.mslot_class);
649 printf
650 ("extended_dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present=%u\n",
651 cm3->extended_dtm_gprs_multislot_cap.
652 extended_dtm_egprs_multislot_cap.present);
653 printf
654 ("extended_dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class=%02x\n",
655 cm3->extended_dtm_gprs_multislot_cap.
656 extended_dtm_egprs_multislot_cap.mslot_class);
657 printf("\n");
658 printf("high_multislot_cap.present=%u\n",
659 cm3->high_multislot_cap.present);
660 printf("high_multislot_cap.value=%02x\n",
661 cm3->high_multislot_cap.value);
662 printf("\n");
663 printf("geran_feature_package_2=%u\n", cm3->geran_feature_package_2);
664 printf("gmsk_multislot_power_prof=%02x\n",
665 cm3->gmsk_multislot_power_prof);
666 printf("psk8_multislot_power_prof=%02x\n",
667 cm3->psk8_multislot_power_prof);
668 printf("\n");
669 printf("t_gsm_400_bands_supp.present=%u\n",
670 cm3->t_gsm_400_bands_supp.present);
671 printf("t_gsm_400_bands_supp.value=%02x\n",
672 cm3->t_gsm_400_bands_supp.value);
673 printf("t_gsm_400_bands_supp.assoc_radio_cap=%02x\n",
674 cm3->t_gsm_400_bands_supp.assoc_radio_cap);
675 printf("\n");
676 printf("dl_advanced_rx_perf=%02x\n", cm3->dl_advanced_rx_perf);
677 printf("dtm_enhancements_cap=%u\n", cm3->dtm_enhancements_cap);
678 printf("\n");
679 printf("dtm_gprs_high_multislot_cap.present=%u\n",
680 cm3->dtm_gprs_high_multislot_cap.present);
681 printf("dtm_gprs_high_multislot_cap.mslot_class=%02x\n",
682 cm3->dtm_gprs_high_multislot_cap.mslot_class);
683 printf("dtm_gprs_high_multislot_cap.offset_required=%u\n",
684 cm3->dtm_gprs_high_multislot_cap.offset_required);
685 printf
686 ("dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.present=%u\n",
687 cm3->dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.
688 present);
689 printf
690 ("dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.mslot_class=%02x\n",
691 cm3->dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.
692 mslot_class);
693 printf("\n");
694 printf("repeated_acch_capability=%u\n", cm3->repeated_acch_capability);
695 printf("\n");
696 printf("gsm_710_assoc_radio_cap.present=%u\n",
697 cm3->gsm_710_assoc_radio_cap.present);
698 printf("gsm_710_assoc_radio_cap.value=%02x\n",
699 cm3->gsm_710_assoc_radio_cap.value);
700 printf("\n");
701 printf("t_gsm_810_assoc_radio_cap.present=%u\n",
702 cm3->t_gsm_810_assoc_radio_cap.present);
703 printf("t_gsm_810_assoc_radio_cap.value=%02x\n",
704 cm3->t_gsm_810_assoc_radio_cap.value);
705 printf("\n");
706 printf("ciphering_mode_setting_cap=%u\n",
707 cm3->ciphering_mode_setting_cap);
708 printf("add_pos_cap=%u\n", cm3->add_pos_cap);
709 printf("e_utra_fdd_supp=%u\n", cm3->e_utra_fdd_supp);
710 printf("e_utra_tdd_supp=%u\n", cm3->e_utra_tdd_supp);
711 printf("e_utra_meas_rep_supp=%u\n", cm3->e_utra_meas_rep_supp);
712 printf("prio_resel_supp=%u\n", cm3->prio_resel_supp);
713 printf("utra_csg_cells_rep=%u\n", cm3->utra_csg_cells_rep);
714 printf("vamos_level=%02x\n", cm3->vamos_level);
715 printf("tighter_capability=%02x\n", cm3->tighter_capability);
716 printf("sel_ciph_dl_sacch=%u\n", cm3->sel_ciph_dl_sacch);
717 printf("cs_ps_srvcc_geran_utra=%02x\n", cm3->cs_ps_srvcc_geran_utra);
718 printf("cs_ps_srvcc_geran_eutra=%02x\n", cm3->cs_ps_srvcc_geran_eutra);
719 printf("geran_net_sharing=%u\n", cm3->geran_net_sharing);
720 printf("e_utra_wb_rsrq_meas_supp=%u\n", cm3->e_utra_wb_rsrq_meas_supp);
721 printf("er_band_support=%u\n", cm3->er_band_support);
722 printf("utra_mult_band_ind_supp=%u\n", cm3->utra_mult_band_ind_supp);
723 printf("e_utra_mult_band_ind_supp=%u\n",
724 cm3->e_utra_mult_band_ind_supp);
725 printf("extended_tsc_set_cap_supp=%u\n",
726 cm3->extended_tsc_set_cap_supp);
727 printf("extended_earfcn_val_range=%u\n",
728 cm3->extended_earfcn_val_range);
729}
730
731static void test_decode_classmark3(void)
732{
733 struct gsm48_classmark3 cm3;
734 const uint8_t cm3_1[] = { 0x60, 0x14, 0x04, 0x2f, 0x65, 0x00, 0x20, 0x03, 0x40, 0x4a };
735 const uint8_t cm3_2[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
736 const uint8_t cm3_3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
737
738 printf("=====cm3_1=====\n");
739 gsm48_decode_classmark3(&cm3, cm3_1, sizeof(cm3_1));
740 dump_cm3(&cm3);
741 printf("\n");
742
743 printf("=====cm3_2=====\n");
744 gsm48_decode_classmark3(&cm3, cm3_2, sizeof(cm3_2));
745 dump_cm3(&cm3);
746 printf("\n");
747
748 printf("=====cm3_3=====\n");
749 gsm48_decode_classmark3(&cm3, cm3_3, sizeof(cm3_3));
750 dump_cm3(&cm3);
751 printf("\n");
752}
753
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200754static void test_mid_from_tmsi(void)
755{
756 static const uint8_t res[] = { 0x17, 0x05, 0xf4, 0xaa, 0xbb, 0xcc, 0xdd };
757
758
759 uint32_t tmsi = 0xAABBCCDD;
760 uint8_t buf[3 + sizeof(uint32_t)];
761
762 printf("Simple TMSI encoding test....");
763
764 memset(&buf, 0xFE, sizeof(buf));
765 gsm48_generate_mid_from_tmsi(buf, tmsi);
766
767 OSMO_ASSERT(memcmp(buf, res, sizeof(res)) == 0);
768 printf("passed\n");
769}
770
Maxd55d7d42018-02-15 11:27:18 +0100771static void test_mid_from_imsi(void)
772{
773 char *imsi = "901700000004620";
774 uint8_t buf[10], len;
775
776 printf("Simple IMSI encoding test....");
777
778 len = gsm48_generate_mid_from_imsi(buf, imsi);
779
780 printf("passed: [%u] %s\n", len, osmo_hexdump(buf, len));
781}
782
Neels Hofmeyr49686282018-12-05 21:32:21 +0100783struct test_mid_encode_decode_test {
784 uint8_t mi_type;
785 const char *mi_str;
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100786 const char *mi_name;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100787 size_t str_size;
788 const char *expect_mi_tlv_hex;
789 const char *expect_str;
790 int expect_rc;
791};
792
793static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = {
794 {
795 .mi_type = GSM_MI_TYPE_IMSI,
796 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100797 .mi_name = "IMSI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100798 .expect_mi_tlv_hex = "17081932547698103254",
799 },
800 {
801 .mi_type = GSM_MI_TYPE_IMSI,
802 .mi_str = "12345678901234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100803 .mi_name = "IMSI-12345678901234",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100804 .expect_mi_tlv_hex = "170811325476981032f4",
805 },
806 {
807 .mi_type = GSM_MI_TYPE_IMSI,
808 .mi_str = "423423",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100809 .mi_name = "IMSI-423423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100810 .expect_mi_tlv_hex = "1704413224f3",
811 },
812 {
813 .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD,
814 .mi_str = "423423",
Harald Weltea13fb752020-06-16 08:44:42 +0200815 .mi_name = "IMSI-423423",
816 .expect_mi_tlv_hex = "1704413224f3",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100817 },
818 {
819 .mi_type = GSM_MI_TYPE_IMSI,
820 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100821 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100822 .expect_mi_tlv_hex = "170449322453",
823 },
824 {
825 .mi_type = GSM_MI_TYPE_IMSI,
826 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100827 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100828 .expect_mi_tlv_hex = "170449322453",
829 .str_size = 4,
830 .expect_str = "423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100831 },
832 {
833 .mi_type = GSM_MI_TYPE_IMEI,
834 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100835 .mi_name = "IMEI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100836 .expect_mi_tlv_hex = "17081a32547698103254",
837 },
838 {
839 .mi_type = GSM_MI_TYPE_IMEI,
840 .mi_str = "98765432109876",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100841 .mi_name = "IMEI-98765432109876",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100842 .expect_mi_tlv_hex = "170892785634129078f6",
843 },
844 {
845 .mi_type = GSM_MI_TYPE_IMEI,
846 .mi_str = "987654321098765",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100847 .mi_name = "IMEI-987654321098765",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100848 .expect_mi_tlv_hex = "17089a78563412907856",
849 },
850 {
851 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100852 .mi_str = "9876543210987654",
853 .mi_name = "IMEI-SV-9876543210987654",
854 .expect_mi_tlv_hex = "17099378563412907856f4",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100855 },
856 {
857 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100858 .mi_str = "9876543210987654",
859 .mi_name = "IMEI-SV-9876543210987654",
860 .expect_mi_tlv_hex = "17099378563412907856f4",
861 .str_size = 17,
862 .expect_str = "9876543210987654",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100863 },
864 {
865 /* gsm48 treats TMSI as decimal string */
866 .mi_type = GSM_MI_TYPE_TMSI,
867 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100868 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100869 .expect_mi_tlv_hex = "1705f412345678",
870 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
871 },
872 {
873 .mi_type = GSM_MI_TYPE_TMSI,
874 .mi_str = "12648430", /* 0xc0ffee as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100875 .mi_name = "TMSI-0x00C0FFEE",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100876 .expect_mi_tlv_hex = "1705f400c0ffee",
877 .expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
878 },
879 {
880 .mi_type = GSM_MI_TYPE_TMSI,
881 .mi_str = "0",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100882 .mi_name = "TMSI-0x00000000",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100883 .expect_mi_tlv_hex = "1705f400000000",
884 .expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
885 },
886 {
887 /* gsm48 treats TMSI as decimal string */
888 .mi_type = GSM_MI_TYPE_TMSI,
889 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100890 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100891 .expect_mi_tlv_hex = "1705f412345678",
892 .str_size = 5,
893 .expect_str = "3054",
894 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns would-be strlen() like snprintf()! */
895 },
896 {
897 .mi_type = GSM_MI_TYPE_NONE,
898 .mi_str = "123",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100899 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200900 .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100901 .expect_str = "",
902 },
903 {
904 .mi_type = GSM_MI_TYPE_NONE,
905 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100906 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200907 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100908 .expect_str = "",
909 },
910 {
911 .mi_type = GSM_MI_ODD,
912 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100913 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200914 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100915 .expect_str = "",
916 },
917};
918
919static void test_mid_encode_decode(void)
920{
921 int i;
922
923 printf("\nTesting Mobile Identity conversions\n");
924
925 for (i = 0; i < ARRAY_SIZE(test_mid_encode_decode_tests); i++) {
926 const struct test_mid_encode_decode_test *t = &test_mid_encode_decode_tests[i];
927 uint8_t tlv_buf[64];
928 uint8_t *mi_buf;
929 int tlv_len;
930 int mi_len;
931 const char *tlv_hex;
932 char str[64] = {};
933 size_t str_size = t->str_size ? : sizeof(str);
934 const char *expect_str = t->expect_str ? : t->mi_str;
935 int expect_rc = t->expect_rc ? : strlen(expect_str)+1;
936 int rc;
937 int str_len;
938
939 printf("- %s %s\n", gsm48_mi_type_name(t->mi_type), t->mi_str);
940 if (t->mi_type == GSM_MI_TYPE_TMSI)
941 tlv_len = gsm48_generate_mid_from_tmsi(tlv_buf, (uint32_t)atoll(t->mi_str));
942 else
943 tlv_len = gsm48_generate_mid(tlv_buf, t->mi_str, t->mi_type);
944 tlv_hex = osmo_hexdump_nospc(tlv_buf, tlv_len);
945
946 printf(" -> MI-TLV-hex='%s'\n", tlv_hex);
947 if (t->expect_mi_tlv_hex && strcmp(tlv_hex, t->expect_mi_tlv_hex)) {
948 printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex);
949 }
950
Harald Weltea13fb752020-06-16 08:44:42 +0200951 /* skip the GSM48_IE_MOBILE_ID tag and length */
952 mi_buf = tlv_buf + 2;
953 mi_len = tlv_len - 2;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100954
955 rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
956 printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc);
957 if (strcmp(str, expect_str))
958 printf(" ERROR: expected MI-str=%s\n", osmo_quote_str(expect_str, -1));
959 if (rc != expect_rc)
960 printf(" ERROR: expected rc=%d\n", expect_rc);
961
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100962 if (t->mi_name) {
963 const char *mi_name = osmo_mi_name(mi_buf, mi_len);
964 printf(" -> MI-name=%s\n", osmo_quote_str(mi_name, -1));
965 if (strcmp(mi_name, t->mi_name))
966 printf(" ERROR: expected MI-name=%s\n", osmo_quote_str(t->mi_name, -1));
967 }
968
Neels Hofmeyr49686282018-12-05 21:32:21 +0100969 /* Now make sure the resulting string is always '\0' terminated.
970 * The above started out with a zeroed buffer, now repeat with a tainted one. */
971 str_len = strlen(str);
972 str[str_len] = '!';
973 gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
974 if (strlen(str) != str_len)
975 printf(" ERROR: resulting string is not explicitly nul terminated\n");
976 }
977}
978
979static const uint8_t test_mid_decode_zero_length_types[] = { GSM_MI_TYPE_IMSI, GSM_MI_TYPE_TMSI, GSM_MI_TYPE_NONE };
980
981static void test_mid_decode_zero_length(void)
982{
983 int odd;
984 uint8_t valid_mi[64];
985 int valid_mi_len;
986
987 printf("\nDecoding zero length Mobile Identities\n");
988
989 /* IMSI = 123456789012345 */
990 valid_mi_len = osmo_hexparse("1932547698103254", valid_mi, sizeof(valid_mi));
991
992 for (odd = 0; odd <= 1; odd++) {
993 int i;
994 for (i = 0; i < ARRAY_SIZE(test_mid_decode_zero_length_types); i++) {
995 uint8_t mi_type = test_mid_decode_zero_length_types[i] | (odd ? GSM_MI_ODD : 0);
996 char str[8] = {};
997 int rc;
998
999 printf("- MI type: %s%s\n", gsm48_mi_type_name(mi_type & GSM_MI_TYPE_MASK),
1000 odd ? " | GSM_MI_ODD":"");
1001 valid_mi[0] = (valid_mi[0] & 0xf0) | mi_type;
1002
1003 printf(" - writing to zero-length string:\n");
1004 memset(str, '!', sizeof(str) - 1);
1005 rc = gsm48_mi_to_string(str, 0, valid_mi, valid_mi_len);
1006 printf(" rc=%d\n", rc);
1007 if (str[0] == '!')
1008 printf(" nothing written\n");
1009 else
1010 printf(" ERROR: Wrote to invalid memory!\n");
1011
1012 printf(" - writing to 1-byte-length string:\n");
1013 memset(str, '!', sizeof(str) - 1);
1014 rc = gsm48_mi_to_string(str, 1, valid_mi, valid_mi_len);
1015 printf(" rc=%d\n", rc);
1016 if (str[0] == '\0')
1017 printf(" returned empty string\n");
1018 else if (str[0] == '!')
1019 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
1020 else
1021 printf(" ERROR: Wrote unexpected string %s\n", osmo_quote_str(str, 5));
1022 if (str[1] != '!')
1023 printf(" ERROR: Wrote to invalid memory!\n");
1024
1025 printf(" - decode zero-length mi:\n");
1026 memset(str, '!', sizeof(str) - 1);
1027 rc = gsm48_mi_to_string(str, sizeof(str), valid_mi, 0);
1028 printf(" rc=%d\n", rc);
1029 if (str[0] == '\0')
1030 printf(" returned empty string\n");
1031 else if (str[0] == '!')
1032 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
1033 else
1034 printf(" ERROR: expected empty string, got output string: %s\n", osmo_quote_str(str, -1));
1035 }
1036 }
1037 printf("\n");
1038}
1039
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001040struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex)
1041{
1042 struct msgb *msg = msgb_alloc_headroom(size, 4, label);
1043 OSMO_ASSERT(msg);
1044 msg->l3h = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
1045 return msg;
1046}
1047
1048struct mobile_identity_tc {
1049 const char *label;
1050 const char *compl_l3_msg;
1051 int expect_rc;
1052 struct osmo_mobile_identity expect_mi;
1053};
1054
1055/* Some Complete Layer 3 messages copied from real GSM network traces. */
1056struct mobile_identity_tc mobile_identity_tests[] = {
1057 {
1058 .label = "LU with IMSI 901700000004620",
1059 .compl_l3_msg = "050802008168000130" "089910070000006402",
1060 .expect_mi = {
1061 .type = GSM_MI_TYPE_IMSI,
1062 .imsi = "901700000004620",
1063 },
1064 },
1065 {
1066 .label = "LU with TMSI 0x0980ad8a",
1067 .compl_l3_msg = "05084262f224002a50" "05f40980ad8a",
1068 .expect_mi = {
1069 .type = GSM_MI_TYPE_TMSI,
1070 .tmsi = 0x0980ad8a,
1071 },
1072 },
1073 {
1074 .label = "LU with invalid MI type",
1075 .compl_l3_msg = "050802008168000130" "089d10070000006402",
1076 .expect_rc = -EINVAL,
1077 },
1078 {
1079 .label = "LU with truncated IMSI MI",
1080 .compl_l3_msg = "050802008168000130" "0899100700000064",
1081 .expect_rc = -EBADMSG,
1082 },
1083 {
1084 .label = "LU with too short IMSI MI (12345)",
1085 .compl_l3_msg = "050802008168000130" "03193254",
1086 .expect_rc = -EBADMSG,
1087 },
1088 {
1089 .label = "LU with just long enough IMSI MI 123456",
1090 .compl_l3_msg = "050802008168000130" "04113254f6",
1091 .expect_mi = {
1092 .type = GSM_MI_TYPE_IMSI,
1093 .imsi = "123456",
1094 },
1095 },
1096 {
1097 .label = "LU with max length IMSI MI 123456789012345",
1098 .compl_l3_msg = "050802008168000130" "081932547698103254",
1099 .expect_mi = {
1100 .type = GSM_MI_TYPE_IMSI,
1101 .imsi = "123456789012345",
1102 },
1103 },
1104 {
1105 .label = "LU with just too long IMSI MI 1234567890123456",
1106 .compl_l3_msg = "050802008168000130" "091132547698103254f6",
1107 .expect_rc = -EBADMSG,
1108 },
1109 {
1110 .label = "LU with truncated TMSI MI",
1111 .compl_l3_msg = "05084262f224002a50" "05f40980ad",
1112 .expect_rc = -EBADMSG,
1113 },
1114 {
1115 .label = "LU with odd length TMSI",
1116 .compl_l3_msg = "05084262f224002a50" "05fc0980ad8a",
1117 .expect_rc = -EBADMSG,
1118 },
1119 {
1120 .label = "LU with too long TMSI MI",
1121 .compl_l3_msg = "05084262f224002a50" "06f40980ad23",
1122 .expect_rc = -EBADMSG,
1123 },
1124 {
1125 .label = "LU with too short TMSI",
1126 .compl_l3_msg = "05084262f224002a50" "04f480ad8a",
1127 .expect_rc = -EBADMSG,
1128 },
1129 {
1130 .label = "CM Service Request with IMSI 123456",
1131 .compl_l3_msg = "052401035058a6" "04113254f6",
1132 .expect_mi = {
1133 .type = GSM_MI_TYPE_IMSI,
1134 .imsi = "123456",
1135 },
1136 },
1137 {
1138 .label = "CM Service Request with TMSI 0x5a42e404",
1139 .compl_l3_msg = "052401035058a6" "05f45a42e404",
1140 .expect_mi = {
1141 .type = GSM_MI_TYPE_TMSI,
1142 .tmsi = 0x5a42e404,
1143 },
1144 },
1145 {
1146 .label = "CM Service Request with shorter CM2, with IMSI 123456",
1147 .compl_l3_msg = "052401025058" "04113254f6",
1148 .expect_mi = {
1149 .type = GSM_MI_TYPE_IMSI,
1150 .imsi = "123456",
1151 },
1152 },
1153 {
1154 .label = "CM Service Request with longer CM2, with IMSI 123456",
1155 .compl_l3_msg = "052401055058a62342" "04113254f6",
1156 .expect_mi = {
1157 .type = GSM_MI_TYPE_IMSI,
1158 .imsi = "123456",
1159 },
1160 },
1161 {
1162 .label = "CM Service Request with shorter CM2, with TMSI 0x00000000",
1163 .compl_l3_msg = "052401025058" "05f400000000",
1164 .expect_mi = {
1165 .type = GSM_MI_TYPE_TMSI,
1166 .tmsi = 0,
1167 },
1168 },
1169 {
1170 .label = "CM Service Request with invalid MI type",
1171 .compl_l3_msg = "052401035058a6" "089d10070000006402",
1172 .expect_rc = -EINVAL,
1173 },
1174 {
1175 .label = "CM Service Request with truncated IMSI MI",
1176 .compl_l3_msg = "052401035058a6" "0899100700000064",
1177 .expect_rc = -EBADMSG,
1178 },
1179 {
1180 .label = "CM Service Request with truncated TMSI MI",
1181 .compl_l3_msg = "0524010150" "05f40980ad",
1182 .expect_rc = -EBADMSG,
1183 },
1184 {
1185 .label = "CM Service Request with odd length TMSI",
1186 .compl_l3_msg = "052401045058a623" "05fc0980ad8a",
1187 .expect_rc = -EBADMSG,
1188 },
1189 {
1190 .label = "CM Service Request with too long TMSI MI",
1191 .compl_l3_msg = "052401035058a6" "06f40980ad23",
1192 .expect_rc = -EBADMSG,
1193 },
1194 {
1195 .label = "CM Service Request with too short TMSI",
1196 .compl_l3_msg = "052401035058a6" "04f480ad8a",
1197 .expect_rc = -EBADMSG,
1198 },
1199 {
1200 .label = "CM Service Reestablish Request with TMSI 0x5a42e404",
1201 .compl_l3_msg = "052801035058a6" "05f45a42e404",
1202 .expect_mi = {
1203 .type = GSM_MI_TYPE_TMSI,
1204 .tmsi = 0x5a42e404,
1205 },
1206 },
1207 {
1208 .label = "Paging Response with IMSI 1234567",
1209 .compl_l3_msg = "06270003505886" "0419325476",
1210 .expect_mi = {
1211 .type = GSM_MI_TYPE_IMSI,
1212 .imsi = "1234567",
1213 },
1214 },
1215 {
1216 .label = "Paging Response with TMSI 0xb48883de",
1217 .compl_l3_msg = "06270003505886" "05f4b48883de",
1218 .expect_mi = {
1219 .type = GSM_MI_TYPE_TMSI,
1220 .tmsi = 0xb48883de,
1221 },
1222 },
1223 {
1224 .label = "Paging Response with TMSI, with unused nibble not 0xf",
1225 .compl_l3_msg = "06270003505886" "0504b48883de",
1226 .expect_rc = -EBADMSG,
1227 },
1228 {
1229 .label = "Paging Response with too short IMEI (1234567)",
1230 .compl_l3_msg = "06270003505886" "041a325476",
1231 .expect_rc = -EBADMSG,
1232 },
1233 {
1234 .label = "Paging Response with IMEI 123456789012345",
1235 .compl_l3_msg = "06270003505886" "081a32547698103254",
1236 .expect_mi = {
1237 .type = GSM_MI_TYPE_IMEI,
1238 .imei = "123456789012345",
1239 },
1240 },
1241 {
1242 .label = "Paging Response with IMEI 12345678901234 (no Luhn checksum)",
1243 .compl_l3_msg = "06270003505886" "0812325476981032f4",
1244 .expect_mi = {
1245 .type = GSM_MI_TYPE_IMEI,
1246 .imei = "12345678901234",
1247 },
1248 },
1249 {
1250 .label = "Paging Response with IMEISV 1234567890123456",
1251 .compl_l3_msg = "06270003505886" "091332547698103254f6",
1252 .expect_mi = {
1253 .type = GSM_MI_TYPE_IMEISV,
1254 .imeisv = "1234567890123456",
1255 },
1256 },
1257 {
1258 .label = "Paging Response with too short IMEISV 123456789012345",
1259 .compl_l3_msg = "06270003505886" "081b32547698103254",
1260 .expect_rc = -EBADMSG,
1261 },
1262 {
1263 .label = "Paging Response with too long IMEISV 12345678901234567",
1264 .compl_l3_msg = "06270003505886" "091b3254769810325476",
1265 .expect_rc = -EBADMSG,
1266 },
1267 {
1268 .label = "Paging Response with IMSI 123456789012345 and flipped ODD bit",
1269 .compl_l3_msg = "06270003505886" "081132547698103254",
1270 .expect_rc = -EBADMSG,
1271 },
1272 {
1273 .label = "IMSI-Detach with IMSI 901700000004620",
1274 .compl_l3_msg = "050130" "089910070000006402",
1275 .expect_mi = {
1276 .type = GSM_MI_TYPE_IMSI,
1277 .imsi = "901700000004620",
1278 },
1279 },
1280 {
1281 .label = "IMSI-Detach with TMSI 0x0980ad8a",
1282 .compl_l3_msg = "050130" "05f40980ad8a",
1283 .expect_mi = {
1284 .type = GSM_MI_TYPE_TMSI,
1285 .tmsi = 0x0980ad8a,
1286 },
1287 },
1288 {
1289 .label = "IMSI-Detach with invalid MI type",
1290 .compl_l3_msg = "050130" "089d10070000006402",
1291 .expect_rc = -EINVAL,
1292 },
1293 {
1294 .label = "IMSI-Detach with truncated IMSI MI",
1295 .compl_l3_msg = "050130" "0899100700000064",
1296 .expect_rc = -EBADMSG,
1297 },
1298 {
1299 .label = "IMSI-Detach with too short IMSI MI (12345)",
1300 .compl_l3_msg = "050130" "03193254",
1301 .expect_rc = -EBADMSG,
1302 },
1303 {
1304 .label = "IMSI-Detach with just long enough IMSI MI 123456",
1305 .compl_l3_msg = "050130" "04113254f6",
1306 .expect_mi = {
1307 .type = GSM_MI_TYPE_IMSI,
1308 .imsi = "123456",
1309 },
1310 },
1311 {
1312 .label = "IMSI-Detach with max length IMSI MI 123456789012345",
1313 .compl_l3_msg = "050130" "081932547698103254",
1314 .expect_mi = {
1315 .type = GSM_MI_TYPE_IMSI,
1316 .imsi = "123456789012345",
1317 },
1318 },
1319 {
1320 .label = "IMSI-Detach with just too long IMSI MI 1234567890123456",
1321 .compl_l3_msg = "050130" "091132547698103254f6",
1322 .expect_rc = -EBADMSG,
1323 },
1324 {
1325 .label = "IMSI-Detach with truncated TMSI MI",
1326 .compl_l3_msg = "050130" "05f40980ad",
1327 .expect_rc = -EBADMSG,
1328 },
1329 {
1330 .label = "IMSI-Detach with odd length TMSI",
1331 .compl_l3_msg = "050130" "05fc0980ad8a",
1332 .expect_rc = -EBADMSG,
1333 },
1334 {
1335 .label = "IMSI-Detach with too long TMSI MI",
1336 .compl_l3_msg = "050130" "06f40980ad23",
1337 .expect_rc = -EBADMSG,
1338 },
1339 {
1340 .label = "IMSI-Detach with too short TMSI",
1341 .compl_l3_msg = "050130" "04f480ad8a",
1342 .expect_rc = -EBADMSG,
1343 },
1344 {
1345 .label = "Identity Response with IMSI 901700000004620",
1346 .compl_l3_msg = "0519" "089910070000006402",
1347 .expect_mi = {
1348 .type = GSM_MI_TYPE_IMSI,
1349 .imsi = "901700000004620",
1350 },
1351 },
1352 {
1353 .label = "Identity Response with IMEI 123456789012345",
1354 .compl_l3_msg = "0519" "081a32547698103254",
1355 .expect_mi = {
1356 .type = GSM_MI_TYPE_IMEI,
1357 .imei = "123456789012345",
1358 },
1359 },
1360 {
1361 .label = "Identity Response with IMEISV 9876543210987654",
1362 .compl_l3_msg = "0519" "099378563412907856f4",
1363 .expect_mi = {
1364 .type = GSM_MI_TYPE_IMEISV,
1365 .imeisv = "9876543210987654",
1366 },
1367 },
1368};
1369
Harald Weltee61d4592022-11-03 11:05:58 +01001370void test_struct_mobile_identity(void)
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001371{
1372 struct mobile_identity_tc *t;
1373 printf("%s()\n", __func__);
1374 for (t = mobile_identity_tests; (t - mobile_identity_tests) < ARRAY_SIZE(mobile_identity_tests); t++) {
1375 struct osmo_mobile_identity mi;
1376 struct msgb *msg;
1377 int rc;
1378 memset(&mi, 0xff, sizeof(mi));
1379
1380 msg = msgb_from_hex(t->label, 1024, t->compl_l3_msg);
1381 rc = osmo_mobile_identity_decode_from_l3(&mi, msg, false);
1382 msgb_free(msg);
1383
Neels Hofmeyra7f97b92022-08-23 18:35:40 +02001384 printf("%s: %s", t->label, rc ? "rc != 0" : "rc == 0");
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001385 if (!rc) {
1386 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
1387 }
1388
1389 if (rc == t->expect_rc
1390 && ((rc != 0) || !osmo_mobile_identity_cmp(&mi, &t->expect_mi))) {
1391 printf(" ok");
1392 } else {
Neels Hofmeyra7f97b92022-08-23 18:35:40 +02001393 printf(" ERROR: Got rc = %d, expected rc = %d", rc, t->expect_rc);
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001394 if (!t->expect_rc)
1395 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &t->expect_mi));
1396 }
1397 printf("\n");
1398 }
1399 printf("\n");
1400}
1401
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001402static const struct bcd_number_test {
1403 /* Human-readable test name */
1404 const char *test_name;
1405
1406 /* To be encoded number in ASCII */
1407 const char *enc_ascii;
1408 /* Expected encoding result in HEX */
1409 const char *enc_hex;
1410 /* Optional header length (LHV) */
1411 uint8_t enc_h_len;
1412 /* Expected return code */
1413 int enc_rc;
1414
1415 /* To be decoded buffer in HEX */
1416 const char *dec_hex;
1417 /* Expected decoding result in ASCII */
1418 const char *dec_ascii;
1419 /* Optional header length (LHV) */
1420 uint8_t dec_h_len;
1421 /* Expected return code */
1422 int dec_rc;
1423
1424 /* Encoding buffer limit (0 means unlimited) */
1425 size_t enc_buf_lim;
1426 /* Decoding buffer limit (0 means unlimited) */
1427 size_t dec_buf_lim;
1428} bcd_number_test_set[] = {
1429 {
1430 .test_name = "regular 9-digit MSISDN",
1431
1432 /* Encoding test */
1433 .enc_ascii = "123456789",
1434 .enc_hex = "0521436587f9",
1435 .enc_rc = 6,
1436
1437 /* Decoding test */
1438 .dec_hex = "0521436587f9",
1439 .dec_ascii = "123456789",
1440 },
1441 {
1442 .test_name = "regular 6-digit MSISDN with optional header (LHV)",
1443
1444 /* Encoding test */
1445 .enc_ascii = "123456",
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001446 .enc_hex = "07ffffffff214365",
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001447 .enc_h_len = 4, /* LHV */
1448 .enc_rc = 4 + 4,
1449
1450 /* Decoding test */
1451 .dec_hex = "07deadbeef214365",
1452 .dec_ascii = "123456",
1453 .dec_h_len = 4, /* LHV */
1454 },
1455 {
1456 .test_name = "long 15-digit (maximum) MSISDN",
1457
1458 /* Encoding test */
1459 .enc_ascii = "123456789012345",
1460 .enc_hex = "0821436587092143f5",
1461 .enc_rc = 9,
1462
1463 /* Decoding test */
1464 .dec_hex = "0821436587092143f5",
1465 .dec_ascii = "123456789012345",
1466 },
1467 {
1468 .test_name = "long 15-digit (maximum) MSISDN, limited buffer",
1469
1470 /* Encoding test */
1471 .enc_ascii = "123456789012345",
1472 .enc_hex = "0821436587092143f5",
1473 .enc_rc = 9,
1474
1475 /* Decoding test */
1476 .dec_hex = "0821436587092143f5",
1477 .dec_ascii = "123456789012345",
1478
1479 /* Buffer length limitations */
1480 .dec_buf_lim = 15 + 1,
1481 .enc_buf_lim = 9,
1482 },
1483 {
1484 .test_name = "to be truncated 20-digit MSISDN",
1485
1486 /* Encoding test (not enough room in buffer) */
1487 .enc_ascii = "12345678901234567890",
1488 .enc_hex = "", /* nothing */
1489 .enc_rc = -EIO,
1490
1491 /* Decoding test (one 5 digits do not fit) */
1492 .dec_hex = "0a21436587092143658709",
1493 .dec_ascii = "123456789012345",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001494 .dec_rc = -ENOSPC,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001495
1496 /* Buffer length limitations */
1497 .dec_buf_lim = 15 + 1, /* 5 digits less */
1498 .enc_buf_lim = 9,
1499 },
1500 {
1501 .test_name = "LV incorrect length",
1502 .dec_hex = "05214365", /* should be 0x03 */
1503 .dec_ascii = "(none)",
Vadim Yanitskiye4799f52019-05-26 00:55:20 +07001504 .dec_rc = -EINVAL,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001505 },
1506 {
1507 .test_name = "empty input buffer",
1508
1509 /* Encoding test */
1510 .enc_ascii = "",
1511 .enc_hex = "00",
1512 .enc_rc = 1,
1513
1514 /* Decoding test */
1515 .dec_hex = "",
1516 .dec_ascii = "(none)",
1517 .dec_rc = -EIO,
1518 },
Oliver Smith186f8782019-06-06 16:11:32 +02001519 {
1520 .test_name = "decoding buffer is one byte too small (OS#4049)",
1521
1522 /* Decoding test */
1523 .dec_hex = "022143", /* "1234" */
1524 .dec_ascii = "123", /* '4' was truncated */
1525 .dec_rc = -ENOSPC,
1526
1527 /* Buffer length limitations */
1528 .dec_buf_lim = 4,
1529 },
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001530};
1531
Harald Weltee61d4592022-11-03 11:05:58 +01001532static void test_bcd_number_encode_decode(void)
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001533{
1534 const struct bcd_number_test *test;
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001535 uint8_t buf_enc[0xff] = { 0xff };
1536 char buf_dec[0xff] = { 0xff };
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001537 size_t buf_len, i;
1538 int rc;
1539
1540 printf("BSD number encoding / decoding test\n");
1541
1542 for (i = 0; i < ARRAY_SIZE(bcd_number_test_set); i++) {
1543 test = &bcd_number_test_set[i];
1544 printf("- Running test: %s\n", test->test_name);
1545
1546 if (test->enc_ascii) {
1547 if (test->enc_buf_lim)
1548 buf_len = test->enc_buf_lim;
1549 else
1550 buf_len = sizeof(buf_enc);
1551
1552 printf(" - Encoding ASCII (buffer limit=%zu) '%s'...\n",
1553 test->enc_buf_lim, test->enc_ascii);
1554
1555 rc = gsm48_encode_bcd_number(buf_enc, buf_len,
1556 test->enc_h_len, test->enc_ascii);
1557 printf(" - Expected: (rc=%d) '%s'\n",
1558 test->enc_rc, test->enc_hex);
1559 printf(" - Actual: (rc=%d) '%s'\n",
1560 rc, osmo_hexdump_nospc(buf_enc, rc >= 0 ? rc : 0));
1561 }
1562
1563 if (test->dec_hex) {
1564 /* Parse a HEX string */
1565 rc = osmo_hexparse(test->dec_hex, buf_enc, sizeof(buf_enc));
1566 OSMO_ASSERT(rc >= 0);
1567
1568 if (test->dec_buf_lim)
1569 buf_len = test->dec_buf_lim;
1570 else
1571 buf_len = sizeof(buf_dec);
1572
1573 printf(" - Decoding HEX (buffer limit=%zu) '%s'...\n",
1574 test->dec_buf_lim, test->dec_hex);
1575
1576 rc = gsm48_decode_bcd_number2(buf_dec, buf_len,
1577 buf_enc, rc, test->dec_h_len);
1578 printf(" - Expected: (rc=%d) '%s'\n",
1579 test->dec_rc, test->dec_ascii);
1580 printf(" - Actual: (rc=%d) '%s'\n",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001581 rc, (rc == 0 || rc == -ENOSPC) ? buf_dec : "(none)");
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001582 }
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001583
1584 /* Poison buffers between the test iterations */
1585 memset(buf_enc, 0xff, sizeof(buf_enc));
1586 memset(buf_dec, 0xff, sizeof(buf_dec));
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001587 }
1588
1589 printf("\n");
1590}
1591
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001592struct {
1593 int range;
1594 int arfcns_num;
1595 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1596} arfcn_test_ranges[] = {
1597 {OSMO_GSM48_ARFCN_RANGE_512, 12,
1598 { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }},
1599 {OSMO_GSM48_ARFCN_RANGE_512, 17,
1600 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }},
1601 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1602 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }},
1603 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1604 { 1, 17, 31, 45, 58, 79, 81, 97,
1605 113, 127, 213, 277, 287, 311, 331, 391,
1606 417, 511 }},
1607 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1608 { 1, 17, 31, 45, 58, 79 }},
1609 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1610 { 10, 17, 31, 45, 58, 79 }},
1611 {OSMO_GSM48_ARFCN_RANGE_1024, 17,
1612 { 0, 17, 31, 45, 58, 79, 81, 97,
1613 113, 127, 213, 277, 287, 311, 331, 391,
1614 1023 }},
1615 {OSMO_GSM48_ARFCN_RANGE_1024, 16,
1616 { 17, 31, 45, 58, 79, 81, 97, 113,
1617 127, 213, 277, 287, 311, 331, 391, 1023 }},
1618 {-1}
1619};
1620
1621static int test_single_range_encoding(int range, const int *orig_arfcns, int arfcns_num, int silent)
1622{
1623 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1624 int w[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1625 int f0_included = 0;
1626 int rc, f0;
1627 uint8_t chan_list[16] = {0};
1628 struct gsm_sysinfo_freq dec_freq[1024] = {{0}};
1629 int dec_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1630 int dec_arfcns_count = 0;
1631 int arfcns_used = 0;
1632 int i;
1633
1634 arfcns_used = arfcns_num;
1635 memmove(arfcns, orig_arfcns, sizeof(arfcns));
1636
1637 f0 = range == OSMO_GSM48_ARFCN_RANGE_1024 ? 0 : arfcns[0];
1638 /*
1639 * Manipulate the ARFCN list according to the rules in J4 depending
1640 * on the selected range.
1641 */
1642 arfcns_used = osmo_gsm48_range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included);
1643
1644 memset(w, 0, sizeof(w));
1645 osmo_gsm48_range_enc_arfcns(range, arfcns, arfcns_used, w, 0);
1646
1647 if (!silent)
1648 printf("range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", range, arfcns_used, f0, f0_included);
1649
1650 /* Select the range and the amount of bits needed */
1651 switch (range) {
1652 case OSMO_GSM48_ARFCN_RANGE_128:
1653 osmo_gsm48_range_enc_128(chan_list, f0, w);
1654 break;
1655 case OSMO_GSM48_ARFCN_RANGE_256:
1656 osmo_gsm48_range_enc_256(chan_list, f0, w);
1657 break;
1658 case OSMO_GSM48_ARFCN_RANGE_512:
1659 osmo_gsm48_range_enc_512(chan_list, f0, w);
1660 break;
1661 case OSMO_GSM48_ARFCN_RANGE_1024:
1662 osmo_gsm48_range_enc_1024(chan_list, f0, f0_included, w);
1663 break;
1664 default:
1665 return 1;
1666 };
1667
1668 if (!silent)
1669 printf("chan_list = %s\n",
1670 osmo_hexdump(chan_list, sizeof(chan_list)));
1671
1672 rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list),
1673 0xfe, 1);
1674 if (rc != 0) {
1675 printf("Cannot decode freq list, rc = %d\n", rc);
1676 return 1;
1677 }
1678
1679 for (i = 0; i < ARRAY_SIZE(dec_freq); i++) {
1680 if (dec_freq[i].mask &&
1681 dec_arfcns_count < ARRAY_SIZE(dec_arfcns))
1682 dec_arfcns[dec_arfcns_count++] = i;
1683 }
1684
1685 if (!silent) {
1686 printf("Decoded freqs %d (expected %d)\n",
1687 dec_arfcns_count, arfcns_num);
1688 printf("Decoded: ");
1689 for (i = 0; i < dec_arfcns_count; i++) {
1690 printf("%d ", dec_arfcns[i]);
1691 if (dec_arfcns[i] != orig_arfcns[i])
1692 printf("(!= %d) ", orig_arfcns[i]);
1693 }
1694 printf("\n");
1695 }
1696
1697 if (dec_arfcns_count != arfcns_num) {
1698 printf("Wrong number of arfcns\n");
1699 return 1;
1700 }
1701
1702 if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) {
1703 printf("Decoding error, got wrong freqs\n");
1704 printf(" w = ");
1705 for (i = 0; i < ARRAY_SIZE(w); i++)
1706 printf("%d ", w[i]);
1707 printf("\n");
1708 return 1;
1709 }
1710
1711 return 0;
1712}
1713
1714static void test_random_range_encoding(int range, int max_arfcn_num)
1715{
1716 int arfcns_num = 0;
1717 int test_idx;
1718 int rc, max_count;
1719 int num_tests = 1024;
1720
1721 printf("Random range test: range %d, max num ARFCNs %d\n",
1722 range, max_arfcn_num);
1723
1724 srandom(1);
1725
1726 for (max_count = 1; max_count < max_arfcn_num; max_count++) {
1727 for (test_idx = 0; test_idx < num_tests; test_idx++) {
1728 int count;
1729 int i;
1730 int min_freq = 0;
1731
1732 int rnd_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1733 char rnd_arfcns_set[1024] = {0};
1734
1735 if (range < OSMO_GSM48_ARFCN_RANGE_1024)
1736 min_freq = random() % (1023 - range);
1737
1738 for (count = max_count; count; ) {
1739 int arfcn = min_freq + random() % (range + 1);
1740 OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set));
1741
1742 if (!rnd_arfcns_set[arfcn]) {
1743 rnd_arfcns_set[arfcn] = 1;
1744 count -= 1;
1745 }
1746 }
1747
1748 arfcns_num = 0;
1749 for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++)
1750 if (rnd_arfcns_set[i])
1751 rnd_arfcns[arfcns_num++] = i;
1752
1753 rc = test_single_range_encoding(range, rnd_arfcns,
1754 arfcns_num, 1);
1755 if (rc != 0) {
1756 printf("Failed on test %d, range %d, num ARFCNs %d\n",
1757 test_idx, range, max_count);
1758 test_single_range_encoding(range, rnd_arfcns,
1759 arfcns_num, 0);
1760 return;
1761 }
1762 }
1763 }
1764}
1765
Harald Weltee61d4592022-11-03 11:05:58 +01001766static void test_range_encoding(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001767{
1768 int *arfcns;
1769 int arfcns_num = 0;
1770 int test_idx;
1771 int range;
1772
1773 for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++)
1774 {
1775 arfcns_num = arfcn_test_ranges[test_idx].arfcns_num;
1776 arfcns = &arfcn_test_ranges[test_idx].arfcns[0];
1777 range = arfcn_test_ranges[test_idx].range;
1778
1779 printf("Range test %d: range %d, num ARFCNs %d\n",
1780 test_idx, range, arfcns_num);
1781
1782 test_single_range_encoding(range, arfcns, arfcns_num, 0);
1783 }
1784
1785 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_128, 29);
1786 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_256, 22);
1787 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_512, 18);
1788 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_1024, 16);
1789}
1790
1791static int freqs1[] = {
1792 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980
1793};
1794
1795static int freqs2[] = {
1796 402, 460, 1, 67, 131, 197, 272, 347,
1797};
1798
1799static int freqs3[] = {
1800 68, 128, 198, 279, 353, 398, 452,
1801
1802};
1803
1804static int w_out[] = {
1805 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9,
1806};
1807
1808static int range128[] = {
1809 1, 1 + 127,
1810};
1811
1812static int range256[] = {
1813 1, 1 + 128,
1814};
1815
1816static int range512[] = {
1817 1, 1+ 511,
1818};
1819
1820
1821#define VERIFY(res, cmp, wanted) \
1822 if (!(res cmp wanted)) { \
1823 printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
1824 __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \
1825 }
1826
Harald Weltee61d4592022-11-03 11:05:58 +01001827static void test_arfcn_filter(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001828{
1829 int arfcns[50], i, res, f0_included;
1830 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1831 arfcns[i] = (i + 1) * 2;
1832
1833 /* check that the arfcn is taken out. f0_included is only set for Range1024 */
1834 f0_included = 24;
1835 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included);
1836 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1837 VERIFY(f0_included, ==, 1);
1838 for (i = 0; i < res; ++i)
1839 VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1));
1840
1841 /* check with range1024, ARFCN 0 is included */
1842 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1843 arfcns[i] = i * 2;
1844 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1845 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1846 VERIFY(f0_included, ==, 1);
1847 for (i = 0; i < res; ++i)
1848 VERIFY(arfcns[i], ==, (i + 1) * 2 - 1);
1849
1850 /* check with range1024, ARFCN 0 not included */
1851 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1852 arfcns[i] = (i + 1) * 2;
1853 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1854 VERIFY(res, ==, ARRAY_SIZE(arfcns));
1855 VERIFY(f0_included, ==, 0);
1856 for (i = 0; i < res; ++i)
1857 VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1);
1858}
1859
Harald Weltee61d4592022-11-03 11:05:58 +01001860static void test_print_encoding(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001861{
1862 int rc;
1863 int w[17];
1864 uint8_t chan_list[16];
1865 memset(chan_list, 0x23, sizeof(chan_list));
1866
1867 for (rc = 0; rc < ARRAY_SIZE(w); ++rc)
1868 switch (rc % 3) {
1869 case 0:
1870 w[rc] = 0xAAAA;
1871 break;
1872 case 1:
1873 w[rc] = 0x5555;
1874 break;
1875 case 2:
1876 w[rc] = 0x9696;
1877 break;
1878 }
1879
1880 osmo_gsm48_range_enc_512(chan_list, (1 << 9) | 0x96, w);
1881
1882 printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list)));
1883}
1884
Harald Weltee61d4592022-11-03 11:05:58 +01001885static void test_si_range_helpers(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001886{
1887 int ws[(sizeof(freqs1)/sizeof(freqs1[0]))];
1888 int i, f0 = 0xFFFFFF;
1889
1890 memset(&ws[0], 0x23, sizeof(ws));
1891
1892 i = osmo_gsm48_range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1));
1893 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1);
1894 VERIFY(i, ==, 2);
1895
1896 i = osmo_gsm48_range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2));
1897 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1);
1898 VERIFY(i, ==, 2);
1899
1900 i = osmo_gsm48_range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3));
1901 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1);
1902 VERIFY(i, ==, 0);
1903
1904 osmo_gsm48_range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0);
1905
1906 for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) {
1907 printf("w[%d]=%d\n", i, ws[i]);
1908 VERIFY(ws[i], ==, w_out[i]);
1909 }
1910
1911 i = osmo_gsm48_range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0);
1912 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_128);
1913 VERIFY(f0, ==, 1);
1914
1915 i = osmo_gsm48_range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0);
1916 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_256);
1917 VERIFY(f0, ==, 1);
1918
1919 i = osmo_gsm48_range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0);
1920 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_512);
1921 VERIFY(f0, ==, 1);
1922}
1923
Harald Weltee61d4592022-11-03 11:05:58 +01001924static void test_power_ctrl(void)
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001925{
1926 int8_t rc8;
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001927 int rc;
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001928
1929 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_850, 0x00);
1930 VERIFY(rc8, ==, 1);
1931 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x02);
1932 VERIFY(rc8, ==, 3);
1933 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1800, 0x02);
1934 VERIFY(rc8, ==, 3);
1935 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x02);
1936 VERIFY(rc8, ==, 3);
1937 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x04);
1938 VERIFY(rc8, <, 0);
1939 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x04);
1940 VERIFY(rc8, ==, 5);
1941 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x05);
1942 VERIFY(rc8, <, 0);
1943 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0xf2);
1944 VERIFY(rc8, <, 0);
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001945
1946 rc = ms_class_gmsk_dbm(GSM_BAND_850, 0);
1947 VERIFY(rc, <, 0);
1948 rc = ms_class_gmsk_dbm(GSM_BAND_850, 1);
1949 VERIFY(rc, ==, 43);
1950 rc = ms_class_gmsk_dbm(GSM_BAND_900, 3);
1951 VERIFY(rc, ==, 37);
1952 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 2);
1953 VERIFY(rc, ==, 24);
1954 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 3);
1955 VERIFY(rc, ==, 36);
1956 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 3);
1957 VERIFY(rc, ==, 33);
1958 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 4);
1959 VERIFY(rc, <, 0);
1960 rc = ms_class_gmsk_dbm(GSM_BAND_900, 5);
1961 VERIFY(rc, ==, 29);
1962 rc = ms_class_gmsk_dbm(GSM_BAND_900, 6);
1963 VERIFY(rc, <, 0);
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001964}
1965
Harald Weltee61d4592022-11-03 11:05:58 +01001966static void test_rach_tx_integer_raw2val(void)
Pau Espin Pedrol1dac8752022-04-26 17:32:33 +02001967{
1968 unsigned int raw;
1969 for (raw = 0; raw <= 0x0f; raw++) {
1970 unsigned int val = rach_tx_integer_raw2val(raw);
1971 printf("rach_tx_integer_raw2val(0x0%x): %u slots used to spread transmission\n",
1972 raw, val);
1973 }
1974}
1975
Philipp Maierb6a38362023-01-12 12:52:57 +01001976static void test_gsm_gsmtime2fn(void)
1977{
1978 struct gsm_time gsm_time;
1979 uint32_t fn;
1980 uint32_t fn_recovered;
1981
1982 for (fn = 0; fn < 42432; fn++) {
1983 gsm_time.t1 = (fn / 1326) % 32;
1984 gsm_time.t2 = fn % 26;
1985 gsm_time.t3 = fn % 51;
1986
1987 fn_recovered = gsm_gsmtime2fn(&gsm_time);
1988
1989 if (fn_recovered != fn) {
1990 printf(" Wrong frame number computed! t1=%d, t2=%d, t3=%d ==> fn=%d, expected fn=%d\n",
1991 gsm_time.t1, gsm_time.t2, gsm_time.t3, fn_recovered, fn);
1992 OSMO_ASSERT(false);
1993 }
1994 }
1995}
1996
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +02001997static void test_gsm_rfn2fn(void)
1998{
1999 unsigned int i;
2000 struct {
2001 uint32_t curr_fn;
2002 uint16_t rfn;
2003 uint32_t exp_fn;
2004 } input[] = {
2005 { .curr_fn = 0, .rfn = 0, .exp_fn = 0 },
2006 { .curr_fn = 0, .rfn = 4, .exp_fn = 4 },
2007 { .curr_fn = 2229729, .rfn = 23322, .exp_fn = 2229786 },
2008 { .curr_fn = 2229777, .rfn = 23322, .exp_fn = 2229786 },
2009 { .curr_fn = 1320458, .rfn = 5070, .exp_fn = 1320462 },
2010 };
2011
2012 for (i = 0; i < ARRAY_SIZE(input); i++) {
2013 uint32_t fn = gsm_rfn2fn(input[i].rfn, input[i].curr_fn);
2014 if (fn != input[i].exp_fn) {
2015 printf("Wrong frame number computed! curr_fn=%u, rfn=%u ==> fn=%u, expected fn=%u\n",
2016 input[i].curr_fn, input[i].rfn, fn, input[i].exp_fn);
2017 OSMO_ASSERT(false);
2018 }
2019 }
2020}
2021
Harald Weltec8a0b932012-08-24 21:27:26 +02002022int main(int argc, char **argv)
2023{
2024 test_bearer_cap();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02002025 test_mid_from_tmsi();
Maxd55d7d42018-02-15 11:27:18 +01002026 test_mid_from_imsi();
Neels Hofmeyr49686282018-12-05 21:32:21 +01002027 test_mid_encode_decode();
2028 test_mid_decode_zero_length();
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02002029 test_struct_mobile_identity();
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07002030 test_bcd_number_encode_decode();
Max99377c22017-08-30 19:17:50 +02002031 test_ra_cap();
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +01002032 test_lai_encode_decode();
Neels Hofmeyr8d423942023-06-08 00:35:41 +02002033 test_osmo_routing_area_id();
Philipp Maiere36be562020-11-12 11:33:54 +01002034 test_decode_classmark3();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02002035
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02002036 test_si_range_helpers();
2037 test_arfcn_filter();
2038 test_print_encoding();
2039 test_range_encoding();
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01002040 test_power_ctrl();
Pau Espin Pedrol1dac8752022-04-26 17:32:33 +02002041 test_rach_tx_integer_raw2val();
Philipp Maierb6a38362023-01-12 12:52:57 +01002042 test_gsm_gsmtime2fn();
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +02002043 test_gsm_rfn2fn();
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02002044
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02002045 return EXIT_SUCCESS;
Harald Weltec8a0b932012-08-24 21:27:26 +02002046}