blob: e82178d45acfc67f3475634fa97d9d892e6b23bf [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 = {
37 .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,
42 .data = {
43 .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,
53 },
54};
55
56static const uint8_t speech_all_lv[] = { 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81 };
57
58static const struct gsm_mncc_bearer_cap bcap_speech_all = {
59 .transfer = GSM48_BCAP_ITCAP_SPEECH,
60 .mode = GSM48_BCAP_TMOD_CIRCUIT,
61 .coding = GSM48_BCAP_CODING_GSM_STD,
62 .radio = GSM48_BCAP_RRQ_DUAL_FR,
63 .speech_ver = {
64 4, 2, 0, 5, 1, -1,
65 },
66};
67
Vadim Yanitskiy95fc8ea2022-07-03 05:41:02 +070068static const uint8_t speech_no3a_lv[] = { 0x01, 0xa0 };
69
70static const struct gsm_mncc_bearer_cap bcap_speech_no3a = {
71 .transfer = GSM48_BCAP_ITCAP_SPEECH,
72 .mode = GSM48_BCAP_TMOD_CIRCUIT,
73 .coding = GSM48_BCAP_CODING_GSM_STD,
74 .radio = GSM48_BCAP_RRQ_FR_ONLY,
75 .speech_ver = {
76 0, -1,
77 },
78};
79
Harald Weltec8a0b932012-08-24 21:27:26 +020080
81struct bcap_test {
82 const uint8_t *lv;
83 const struct gsm_mncc_bearer_cap *bc;
84 const char *name;
85};
86
87static const struct bcap_test bcap_tests[] = {
88 { csd_9600_v110_lv, &bcap_csd_9600_v110, "CSD 9600/V.110/transparent" },
89 { speech_all_lv, &bcap_speech_all, "Speech, all codecs" },
Vadim Yanitskiy95fc8ea2022-07-03 05:41:02 +070090 { speech_no3a_lv, &bcap_speech_no3a, "Speech, without octet 3a" },
Harald Weltec8a0b932012-08-24 21:27:26 +020091};
92
Harald Weltee61d4592022-11-03 11:05:58 +010093static int test_bearer_cap(void)
Harald Weltec8a0b932012-08-24 21:27:26 +020094{
95 struct gsm_mncc_bearer_cap bc;
96 int i, rc;
97
98 for (i = 0; i < ARRAY_SIZE(bcap_tests); i++) {
99 struct msgb *msg = msgb_alloc(100, "test");
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700100 bool pass = false;
Harald Weltec8a0b932012-08-24 21:27:26 +0200101 int lv_len;
102
103 memset(&bc, 0, sizeof(bc));
104
105 /* test decoding */
106 rc = gsm48_decode_bearer_cap(&bc, bcap_tests[i].lv);
107 if (rc < 0) {
108 fprintf(stderr, "Error decoding %s\n",
109 bcap_tests[i].name);
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700110 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200111 }
112 if (memcmp(&bc, bcap_tests[i].bc, sizeof(bc))) {
113 fprintf(stderr, "Incorrect decoded result of %s:\n",
114 bcap_tests[i].name);
115 fprintf(stderr, " should: %s\n",
116 osmo_hexdump((uint8_t *) bcap_tests[i].bc, sizeof(bc)));
117 fprintf(stderr, " is: %s\n",
118 osmo_hexdump((uint8_t *) &bc, sizeof(bc)));
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700119 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200120 }
121
122 /* also test re-encode? */
123 rc = gsm48_encode_bearer_cap(msg, 1, &bc);
124 if (rc < 0) {
125 fprintf(stderr, "Error encoding %s\n",
126 bcap_tests[i].name);
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700127 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200128 }
129 lv_len = bcap_tests[i].lv[0]+1;
130 if (memcmp(msg->data, bcap_tests[i].lv, lv_len)) {
131 fprintf(stderr, "Incorrect encoded result of %s:\n",
132 bcap_tests[i].name);
133 fprintf(stderr, " should: %s\n",
134 osmo_hexdump(bcap_tests[i].lv, lv_len));
135 fprintf(stderr, " is: %s\n",
136 osmo_hexdump(msg->data, msg->len));
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700137 goto verdict;
Harald Weltec8a0b932012-08-24 21:27:26 +0200138 }
139
Vadim Yanitskiy1a077cb2022-07-03 05:53:28 +0700140 /* all checks passed */
141 pass = true;
142
143verdict:
144 printf("Test `%s' %sed\n", bcap_tests[i].name, pass ? "pass" : "fail");
Harald Weltec8a0b932012-08-24 21:27:26 +0200145 msgb_free(msg);
146 }
147
148 return 0;
149}
150
Max99377c22017-08-30 19:17:50 +0200151static inline void dump_ra(const struct gprs_ra_id *raid)
152{
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100153 printf("%s%s\n", osmo_rai_name(raid), raid->mnc_3_digits ? " (3-digit MNC)" : "");
Max99377c22017-08-30 19:17:50 +0200154}
155
156static inline void check_ra(const struct gprs_ra_id *raid)
157{
Maxf1ad60e2018-01-05 14:19:33 +0100158 struct gsm48_ra_id ra;
Max99377c22017-08-30 19:17:50 +0200159 struct gprs_ra_id raid0 = {
160 .mnc = 0,
161 .mcc = 0,
162 .lac = 0,
163 .rac = 0,
164 };
165
Maxf1ad60e2018-01-05 14:19:33 +0100166 gsm48_encode_ra(&ra, raid);
167 printf("Constructed RA:\n");
Max99377c22017-08-30 19:17:50 +0200168
Maxf1ad60e2018-01-05 14:19:33 +0100169 gsm48_parse_ra(&raid0, (const uint8_t *)&ra);
Max99377c22017-08-30 19:17:50 +0200170 dump_ra(raid);
Neels Hofmeyrc38b32d2018-02-20 15:13:18 +0100171 printf("MCC+MNC in BCD: %s\n", osmo_hexdump(ra.digits, sizeof(ra.digits)));
Max99377c22017-08-30 19:17:50 +0200172 dump_ra(&raid0);
173 printf("RA test...");
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100174 if (raid->mnc != raid0.mnc || raid->mcc != raid0.mcc || raid->lac != raid0.lac || raid->rac != raid0.rac
175 || (raid->mnc_3_digits || raid->mnc > 99) != raid0.mnc_3_digits)
Max99377c22017-08-30 19:17:50 +0200176 printf("FAIL\n");
177 else
178 printf("passed\n");
179}
180
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100181static inline void check_lai(const struct gprs_ra_id *raid)
182{
183 int rc;
184 struct gsm48_loc_area_id lai = {};
185 struct gprs_ra_id decoded = {};
186 struct gprs_ra_id _laid = *raid;
187 struct gprs_ra_id *laid = &_laid;
188 laid->rac = 0;
189
190 printf("- gsm48_generate_lai() from "); dump_ra(laid);
191
192 gsm48_generate_lai(&lai, laid->mcc, laid->mnc, laid->lac);
193 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
194 rc = gsm48_decode_lai(&lai, &decoded.mcc, &decoded.mnc, &decoded.lac);
195 if (rc) {
196 printf(" gsm48_decode_lai() returned %d --> FAIL\n", rc);
197 return;
198 }
199 printf(" gsm48_decode_lai() gives "); dump_ra(&decoded);
200 if (decoded.mcc == laid->mcc
201 && decoded.mnc == laid->mnc
202 && decoded.lac == laid->lac)
203 printf(" passed\n");
204 else
205 printf(" FAIL\n");
206}
207
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100208static inline void dump_lai(const struct osmo_location_area_id *lai)
209{
210 printf("%s%s\n", osmo_lai_name(lai), lai->plmn.mnc_3_digits ? " (3-digit MNC)" : "");
211}
212
213static inline void check_lai2(const struct gprs_ra_id *raid)
214{
215 struct gsm48_loc_area_id lai = {};
216 struct osmo_location_area_id decoded = {};
217 struct osmo_location_area_id laid = {
218 .plmn = {
219 .mcc = raid->mcc,
220 .mnc = raid->mnc,
221 .mnc_3_digits = raid->mnc_3_digits,
222 },
223 .lac = raid->lac,
224 };
225
226 printf("- gsm48_generate_lai2() from "); dump_lai(&laid);
227
228 gsm48_generate_lai2(&lai, &laid);
229 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
230 gsm48_decode_lai2(&lai, &decoded);
231 printf(" gsm48_decode_lai2() gives "); dump_lai(&decoded);
232 if (decoded.plmn.mcc == laid.plmn.mcc
233 && decoded.plmn.mnc == laid.plmn.mnc
234 && decoded.lac == laid.lac
235 && decoded.plmn.mnc_3_digits == (laid.plmn.mnc_3_digits || laid.plmn.mnc > 99))
236 printf(" passed\n");
237 else
238 printf(" FAIL\n");
239}
240
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100241static struct gprs_ra_id test_ra_cap_items[] = {
242 {
Max99377c22017-08-30 19:17:50 +0200243 .mcc = 77,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100244 .mnc = 121,
Max99377c22017-08-30 19:17:50 +0200245 .lac = 666,
246 .rac = 5,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100247 },
248 {
Max99377c22017-08-30 19:17:50 +0200249 .mcc = 84,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100250 .mnc = 98,
Max99377c22017-08-30 19:17:50 +0200251 .lac = 11,
252 .rac = 89,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100253 },
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100254 {
255 .mcc = 0,
256 .mnc = 0,
257 .lac = 0,
258 .rac = 0,
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100259 .mnc_3_digits = false,
260 /* expecting 000-00, BCD = 00 f0 00 */
261 },
262 {
263 .mcc = 0,
264 .mnc = 0,
265 .lac = 0,
266 .rac = 0,
267 .mnc_3_digits = true,
268 /* expecting 000-000, BCD = 00 00 00 */
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100269 },
270 {
271 .mcc = 999,
272 .mnc = 999,
273 .lac = 65535,
274 .rac = 255,
275 },
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100276 {
277 .mcc = 1,
278 .mnc = 2,
279 .lac = 23,
280 .rac = 42,
281 .mnc_3_digits = false,
282 /* expecting 001-02, BCD = 00 f1 20 */
283 },
284 {
285 .mcc = 1,
286 .mnc = 2,
287 .lac = 23,
288 .rac = 42,
289 .mnc_3_digits = true,
290 /* expecting 001-002, BCD = 00 21 00 */
291 },
292 {
293 .mcc = 12,
294 .mnc = 34,
295 .lac = 56,
296 .rac = 78,
297 .mnc_3_digits = false,
298 /* expecting 012-34, BCD = 10 f2 43 */
299 },
300 {
301 .mcc = 12,
302 .mnc = 34,
303 .lac = 23,
304 .rac = 42,
305 .mnc_3_digits = true,
306 /* expecting 012-034, BCD = 10 42 30 */
307 },
308 {
309 .mcc = 123,
310 .mnc = 456,
311 .lac = 23,
312 .rac = 42,
313 .mnc_3_digits = false,
314 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
315 },
316 {
317 .mcc = 123,
318 .mnc = 456,
319 .lac = 23,
320 .rac = 42,
321 .mnc_3_digits = true,
322 /* expecting 123-456, BCD = 21 63 54 (same) */
323 },
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100324};
Max99377c22017-08-30 19:17:50 +0200325
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100326static void test_ra_cap(void)
327{
328 int i;
329
330 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++)
331 check_ra(&test_ra_cap_items[i]);
Max99377c22017-08-30 19:17:50 +0200332}
333
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100334static void test_lai_encode_decode(void)
335{
336 int i;
337
338 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++) {
339 check_lai(&test_ra_cap_items[i]);
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100340 check_lai2(&test_ra_cap_items[i]);
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100341 }
342}
343
Neels Hofmeyr8d423942023-06-08 00:35:41 +0200344static struct osmo_routing_area_id test_osmo_routing_area_id_items[] = {
345 {
346 .lac = {
347 .plmn = {
348 .mcc = 77,
349 .mnc = 121,
350 },
351 .lac = 666,
352 },
353 .rac = 5,
354 },
355 {
356 .lac = {
357 .plmn = {
358 .mcc = 84,
359 .mnc = 98,
360 },
361 .lac = 11,
362 },
363 .rac = 89,
364 },
365 {
366 .lac = {
367 .plmn = {
368 .mcc = 0,
369 .mnc = 0,
370 .mnc_3_digits = false,
371 /* expecting 000-00, BCD = 00 f0 00 */
372 },
373 .lac = 0,
374 },
375 .rac = 0,
376 },
377 {
378 .lac = {
379 .plmn = {
380 .mcc = 0,
381 .mnc = 0,
382 .mnc_3_digits = true,
383 /* expecting 000-000, BCD = 00 00 00 */
384 },
385 .lac = 0,
386 },
387 .rac = 0,
388 },
389 {
390 .lac = {
391 .plmn = {
392 .mcc = 999,
393 .mnc = 999,
394 },
395 .lac = 65535,
396 },
397 .rac = 255,
398 },
399 {
400 .lac = {
401 .plmn = {
402 .mcc = 1,
403 .mnc = 2,
404 .mnc_3_digits = false,
405 /* expecting 001-02, BCD = 00 f1 20 */
406 },
407 .lac = 23,
408 },
409 .rac = 42,
410 },
411 {
412 .lac = {
413 .plmn = {
414 .mcc = 1,
415 .mnc = 2,
416 .mnc_3_digits = true,
417 /* expecting 001-002, BCD = 00 21 00 */
418 },
419 .lac = 23,
420 },
421 .rac = 42,
422 },
423 {
424 .lac = {
425 .plmn = {
426 .mcc = 12,
427 .mnc = 34,
428 .mnc_3_digits = false,
429 /* expecting 012-34, BCD = 10 f2 43 */
430 },
431 .lac = 56,
432 },
433 .rac = 78,
434 },
435 {
436 .lac = {
437 .plmn = {
438 .mcc = 12,
439 .mnc = 34,
440 .mnc_3_digits = true,
441 /* expecting 012-034, BCD = 10 42 30 */
442 },
443 .lac = 23,
444 },
445 .rac = 42,
446 },
447 {
448 .lac = {
449 .plmn = {
450 .mcc = 123,
451 .mnc = 456,
452 .mnc_3_digits = false,
453 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
454 },
455 .lac = 23,
456 },
457 .rac = 42,
458 },
459 {
460 .lac = {
461 .plmn = {
462 .mcc = 123,
463 .mnc = 456,
464 .mnc_3_digits = true,
465 /* expecting 123-456, BCD = 21 63 54 (same) */
466 },
467 .lac = 23,
468 },
469 .rac = 42,
470 },
471};
472
473static inline void dump_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
474{
475 printf("%s%s", osmo_rai_name2(raid), raid->lac.plmn.mnc_3_digits ? " (3-digit MNC)" : "");
476}
477
478static inline void check_osmo_routing_area_id(const struct osmo_routing_area_id *raid)
479{
480 uint8_t buf[sizeof(struct gsm48_ra_id)] = {};
481 struct osmo_routing_area_id raid0 = {};
482 int rc;
483
484 printf("RA ID: ");
485 dump_osmo_routing_area_id(raid);
486
487 rc = osmo_routing_area_id_encode_buf(buf, sizeof(buf), raid);
488 printf("osmo_routing_area_id_encode_buf(): %src=%d\n", osmo_hexdump(buf, sizeof(buf)), rc);
489
490 rc = osmo_routing_area_id_decode(&raid0, buf, sizeof(buf));
491 printf("osmo_routing_area_id_decode(): ");
492 dump_osmo_routing_area_id(&raid0);
493 printf(" rc=%d\n", rc);
494
495 if (osmo_rai_cmp(raid, &raid0))
496 printf("FAIL\n");
497 else
498 printf("ok\n");
499}
500
501static void test_osmo_routing_area_id(void)
502{
503 int i;
504 printf("==%s()==\n", __func__);
505 for (i = 0; i < ARRAY_SIZE(test_osmo_routing_area_id_items); i++)
506 check_osmo_routing_area_id(&test_osmo_routing_area_id_items[i]);
507}
508
Philipp Maiere36be562020-11-12 11:33:54 +0100509static void dump_cm3(struct gsm48_classmark3 *cm3)
510{
511 printf("mult_band_supp=%02x\n", cm3->mult_band_supp);
512 printf("a5_bits=%02x\n", cm3->a5_bits);
513 printf("assoc_radio_cap_1=%02x\n", cm3->assoc_radio_cap_1);
514 printf("assoc_radio_cap_2=%02x\n", cm3->assoc_radio_cap_2);
515 printf("\n");
516 printf("r_support.present=%u\n", cm3->r_support.present);
517 printf("r_support.r_gsm_assoc_radio_cap=%02x\n",
518 cm3->r_support.r_gsm_assoc_radio_cap);
519 printf("\n");
520 printf("hscsd_mult_slot_cap.present=%u\n",
521 cm3->hscsd_mult_slot_cap.present);
522 printf("hscsd_mult_slot_cap.mslot_class=%02x\n",
523 cm3->hscsd_mult_slot_cap.mslot_class);
524 printf("\n");
525 printf("ucs2_treatment=%u\n", cm3->ucs2_treatment);
526 printf("extended_meas_cap=%u\n", cm3->extended_meas_cap);
527 printf("\n");
528 printf("ms_meas_cap.present=%u\n", cm3->ms_meas_cap.present);
529 printf("ms_meas_cap.sms_value=%02x\n", cm3->ms_meas_cap.sms_value);
530 printf("ms_meas_cap.sm_value=%02x\n", cm3->ms_meas_cap.sm_value);
531 printf("\n");
532 printf("ms_pos_method_cap.present=%u\n",
533 cm3->ms_pos_method_cap.present);
534 printf("ms_pos_method_cap.method=%02x\n",
535 cm3->ms_pos_method_cap.method);
536 printf("\n");
537 printf("ecsd_multislot_cap.present=%u\n",
538 cm3->ecsd_multislot_cap.present);
539 printf("ecsd_multislot_cap.mslot_class=%02x\n",
540 cm3->ecsd_multislot_cap.mslot_class);
541 printf("\n");
542 printf("psk8_struct.present=%u\n", cm3->psk8_struct.present);
543 printf("psk8_struct.mod_cap=%u\n", cm3->psk8_struct.mod_cap);
544 printf("psk8_struct.rf_pwr_cap_1.present=%u\n",
545 cm3->psk8_struct.rf_pwr_cap_1.present);
546 printf("psk8_struct.rf_pwr_cap_1.value=%02x\n",
547 cm3->psk8_struct.rf_pwr_cap_1.value);
548 printf("psk8_struct.rf_pwr_cap_2.present=%u\n",
549 cm3->psk8_struct.rf_pwr_cap_2.present);
550 printf("psk8_struct.rf_pwr_cap_2.value=%02x\n",
551 cm3->psk8_struct.rf_pwr_cap_2.value);
552 printf("\n");
553 printf("gsm_400_bands_supp.present=%u\n",
554 cm3->gsm_400_bands_supp.present);
555 printf("gsm_400_bands_supp.value=%02x\n",
556 cm3->gsm_400_bands_supp.value);
557 printf("gsm_400_bands_supp.assoc_radio_cap=%02x\n",
558 cm3->gsm_400_bands_supp.assoc_radio_cap);
559 printf("\n");
560 printf("gsm_850_assoc_radio_cap.present=%u\n",
561 cm3->gsm_850_assoc_radio_cap.present);
562 printf("gsm_850_assoc_radio_cap.value=%02x\n",
563 cm3->gsm_850_assoc_radio_cap.value);
564 printf("\n");
565 printf("gsm_1900_assoc_radio_cap.present=%u\n",
566 cm3->gsm_1900_assoc_radio_cap.present);
567 printf("gsm_1900_assoc_radio_cap.value=%02x\n",
568 cm3->gsm_1900_assoc_radio_cap.value);
569 printf("\n");
570 printf("umts_fdd_rat_cap=%u\n", cm3->umts_fdd_rat_cap);
571 printf("umts_tdd_rat_cap=%u\n", cm3->umts_tdd_rat_cap);
572 printf("cdma200_rat_cap=%u\n", cm3->cdma200_rat_cap);
573 printf("\n");
574 printf("dtm_gprs_multislot_cap.present=%u\n",
575 cm3->dtm_gprs_multislot_cap.present);
576 printf("dtm_gprs_multislot_cap.mslot_class=%02x\n",
577 cm3->dtm_gprs_multislot_cap.mslot_class);
578 printf("dtm_gprs_multislot_cap.single_slot_dtm=%u\n",
579 cm3->dtm_gprs_multislot_cap.single_slot_dtm);
580 printf("dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present=%u\n",
581 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present);
582 printf("dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class=%02x\n",
583 cm3->dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class);
584 printf("\n");
585 printf("single_band_supp.present=%u\n", cm3->single_band_supp.present);
586 printf("single_band_supp.value=%u\n", cm3->single_band_supp.value);
587 printf("\n");
588 printf("gsm_750_assoc_radio_cap.present=%u\n",
589 cm3->gsm_750_assoc_radio_cap.present);
590 printf("gsm_750_assoc_radio_cap.value=%02x\n",
591 cm3->gsm_750_assoc_radio_cap.value);
592 printf("\n");
593 printf("umts_1_28_mcps_tdd_rat_cap=%u\n",
594 cm3->umts_1_28_mcps_tdd_rat_cap);
595 printf("geran_feature_package=%u\n", cm3->geran_feature_package);
596 printf("\n");
597 printf("extended_dtm_gprs_multislot_cap.present=%u\n",
598 cm3->extended_dtm_gprs_multislot_cap.present);
599 printf("extended_dtm_gprs_multislot_cap.mslot_class=%02x\n",
600 cm3->extended_dtm_gprs_multislot_cap.mslot_class);
601 printf
602 ("extended_dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.present=%u\n",
603 cm3->extended_dtm_gprs_multislot_cap.
604 extended_dtm_egprs_multislot_cap.present);
605 printf
606 ("extended_dtm_gprs_multislot_cap.dtm_egprs_multislot_cap.mslot_class=%02x\n",
607 cm3->extended_dtm_gprs_multislot_cap.
608 extended_dtm_egprs_multislot_cap.mslot_class);
609 printf("\n");
610 printf("high_multislot_cap.present=%u\n",
611 cm3->high_multislot_cap.present);
612 printf("high_multislot_cap.value=%02x\n",
613 cm3->high_multislot_cap.value);
614 printf("\n");
615 printf("geran_feature_package_2=%u\n", cm3->geran_feature_package_2);
616 printf("gmsk_multislot_power_prof=%02x\n",
617 cm3->gmsk_multislot_power_prof);
618 printf("psk8_multislot_power_prof=%02x\n",
619 cm3->psk8_multislot_power_prof);
620 printf("\n");
621 printf("t_gsm_400_bands_supp.present=%u\n",
622 cm3->t_gsm_400_bands_supp.present);
623 printf("t_gsm_400_bands_supp.value=%02x\n",
624 cm3->t_gsm_400_bands_supp.value);
625 printf("t_gsm_400_bands_supp.assoc_radio_cap=%02x\n",
626 cm3->t_gsm_400_bands_supp.assoc_radio_cap);
627 printf("\n");
628 printf("dl_advanced_rx_perf=%02x\n", cm3->dl_advanced_rx_perf);
629 printf("dtm_enhancements_cap=%u\n", cm3->dtm_enhancements_cap);
630 printf("\n");
631 printf("dtm_gprs_high_multislot_cap.present=%u\n",
632 cm3->dtm_gprs_high_multislot_cap.present);
633 printf("dtm_gprs_high_multislot_cap.mslot_class=%02x\n",
634 cm3->dtm_gprs_high_multislot_cap.mslot_class);
635 printf("dtm_gprs_high_multislot_cap.offset_required=%u\n",
636 cm3->dtm_gprs_high_multislot_cap.offset_required);
637 printf
638 ("dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.present=%u\n",
639 cm3->dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.
640 present);
641 printf
642 ("dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.mslot_class=%02x\n",
643 cm3->dtm_gprs_high_multislot_cap.dtm_egprs_high_multislot_cap.
644 mslot_class);
645 printf("\n");
646 printf("repeated_acch_capability=%u\n", cm3->repeated_acch_capability);
647 printf("\n");
648 printf("gsm_710_assoc_radio_cap.present=%u\n",
649 cm3->gsm_710_assoc_radio_cap.present);
650 printf("gsm_710_assoc_radio_cap.value=%02x\n",
651 cm3->gsm_710_assoc_radio_cap.value);
652 printf("\n");
653 printf("t_gsm_810_assoc_radio_cap.present=%u\n",
654 cm3->t_gsm_810_assoc_radio_cap.present);
655 printf("t_gsm_810_assoc_radio_cap.value=%02x\n",
656 cm3->t_gsm_810_assoc_radio_cap.value);
657 printf("\n");
658 printf("ciphering_mode_setting_cap=%u\n",
659 cm3->ciphering_mode_setting_cap);
660 printf("add_pos_cap=%u\n", cm3->add_pos_cap);
661 printf("e_utra_fdd_supp=%u\n", cm3->e_utra_fdd_supp);
662 printf("e_utra_tdd_supp=%u\n", cm3->e_utra_tdd_supp);
663 printf("e_utra_meas_rep_supp=%u\n", cm3->e_utra_meas_rep_supp);
664 printf("prio_resel_supp=%u\n", cm3->prio_resel_supp);
665 printf("utra_csg_cells_rep=%u\n", cm3->utra_csg_cells_rep);
666 printf("vamos_level=%02x\n", cm3->vamos_level);
667 printf("tighter_capability=%02x\n", cm3->tighter_capability);
668 printf("sel_ciph_dl_sacch=%u\n", cm3->sel_ciph_dl_sacch);
669 printf("cs_ps_srvcc_geran_utra=%02x\n", cm3->cs_ps_srvcc_geran_utra);
670 printf("cs_ps_srvcc_geran_eutra=%02x\n", cm3->cs_ps_srvcc_geran_eutra);
671 printf("geran_net_sharing=%u\n", cm3->geran_net_sharing);
672 printf("e_utra_wb_rsrq_meas_supp=%u\n", cm3->e_utra_wb_rsrq_meas_supp);
673 printf("er_band_support=%u\n", cm3->er_band_support);
674 printf("utra_mult_band_ind_supp=%u\n", cm3->utra_mult_band_ind_supp);
675 printf("e_utra_mult_band_ind_supp=%u\n",
676 cm3->e_utra_mult_band_ind_supp);
677 printf("extended_tsc_set_cap_supp=%u\n",
678 cm3->extended_tsc_set_cap_supp);
679 printf("extended_earfcn_val_range=%u\n",
680 cm3->extended_earfcn_val_range);
681}
682
683static void test_decode_classmark3(void)
684{
685 struct gsm48_classmark3 cm3;
686 const uint8_t cm3_1[] = { 0x60, 0x14, 0x04, 0x2f, 0x65, 0x00, 0x20, 0x03, 0x40, 0x4a };
687 const uint8_t cm3_2[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
688 const uint8_t cm3_3[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
689
690 printf("=====cm3_1=====\n");
691 gsm48_decode_classmark3(&cm3, cm3_1, sizeof(cm3_1));
692 dump_cm3(&cm3);
693 printf("\n");
694
695 printf("=====cm3_2=====\n");
696 gsm48_decode_classmark3(&cm3, cm3_2, sizeof(cm3_2));
697 dump_cm3(&cm3);
698 printf("\n");
699
700 printf("=====cm3_3=====\n");
701 gsm48_decode_classmark3(&cm3, cm3_3, sizeof(cm3_3));
702 dump_cm3(&cm3);
703 printf("\n");
704}
705
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200706static void test_mid_from_tmsi(void)
707{
708 static const uint8_t res[] = { 0x17, 0x05, 0xf4, 0xaa, 0xbb, 0xcc, 0xdd };
709
710
711 uint32_t tmsi = 0xAABBCCDD;
712 uint8_t buf[3 + sizeof(uint32_t)];
713
714 printf("Simple TMSI encoding test....");
715
716 memset(&buf, 0xFE, sizeof(buf));
717 gsm48_generate_mid_from_tmsi(buf, tmsi);
718
719 OSMO_ASSERT(memcmp(buf, res, sizeof(res)) == 0);
720 printf("passed\n");
721}
722
Maxd55d7d42018-02-15 11:27:18 +0100723static void test_mid_from_imsi(void)
724{
725 char *imsi = "901700000004620";
726 uint8_t buf[10], len;
727
728 printf("Simple IMSI encoding test....");
729
730 len = gsm48_generate_mid_from_imsi(buf, imsi);
731
732 printf("passed: [%u] %s\n", len, osmo_hexdump(buf, len));
733}
734
Neels Hofmeyr49686282018-12-05 21:32:21 +0100735struct test_mid_encode_decode_test {
736 uint8_t mi_type;
737 const char *mi_str;
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100738 const char *mi_name;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100739 size_t str_size;
740 const char *expect_mi_tlv_hex;
741 const char *expect_str;
742 int expect_rc;
743};
744
745static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = {
746 {
747 .mi_type = GSM_MI_TYPE_IMSI,
748 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100749 .mi_name = "IMSI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100750 .expect_mi_tlv_hex = "17081932547698103254",
751 },
752 {
753 .mi_type = GSM_MI_TYPE_IMSI,
754 .mi_str = "12345678901234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100755 .mi_name = "IMSI-12345678901234",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100756 .expect_mi_tlv_hex = "170811325476981032f4",
757 },
758 {
759 .mi_type = GSM_MI_TYPE_IMSI,
760 .mi_str = "423423",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100761 .mi_name = "IMSI-423423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100762 .expect_mi_tlv_hex = "1704413224f3",
763 },
764 {
765 .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD,
766 .mi_str = "423423",
Harald Weltea13fb752020-06-16 08:44:42 +0200767 .mi_name = "IMSI-423423",
768 .expect_mi_tlv_hex = "1704413224f3",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100769 },
770 {
771 .mi_type = GSM_MI_TYPE_IMSI,
772 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100773 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100774 .expect_mi_tlv_hex = "170449322453",
775 },
776 {
777 .mi_type = GSM_MI_TYPE_IMSI,
778 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100779 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100780 .expect_mi_tlv_hex = "170449322453",
781 .str_size = 4,
782 .expect_str = "423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100783 },
784 {
785 .mi_type = GSM_MI_TYPE_IMEI,
786 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100787 .mi_name = "IMEI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100788 .expect_mi_tlv_hex = "17081a32547698103254",
789 },
790 {
791 .mi_type = GSM_MI_TYPE_IMEI,
792 .mi_str = "98765432109876",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100793 .mi_name = "IMEI-98765432109876",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100794 .expect_mi_tlv_hex = "170892785634129078f6",
795 },
796 {
797 .mi_type = GSM_MI_TYPE_IMEI,
798 .mi_str = "987654321098765",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100799 .mi_name = "IMEI-987654321098765",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100800 .expect_mi_tlv_hex = "17089a78563412907856",
801 },
802 {
803 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100804 .mi_str = "9876543210987654",
805 .mi_name = "IMEI-SV-9876543210987654",
806 .expect_mi_tlv_hex = "17099378563412907856f4",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100807 },
808 {
809 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100810 .mi_str = "9876543210987654",
811 .mi_name = "IMEI-SV-9876543210987654",
812 .expect_mi_tlv_hex = "17099378563412907856f4",
813 .str_size = 17,
814 .expect_str = "9876543210987654",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100815 },
816 {
817 /* gsm48 treats TMSI as decimal string */
818 .mi_type = GSM_MI_TYPE_TMSI,
819 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100820 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100821 .expect_mi_tlv_hex = "1705f412345678",
822 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
823 },
824 {
825 .mi_type = GSM_MI_TYPE_TMSI,
826 .mi_str = "12648430", /* 0xc0ffee as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100827 .mi_name = "TMSI-0x00C0FFEE",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100828 .expect_mi_tlv_hex = "1705f400c0ffee",
829 .expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
830 },
831 {
832 .mi_type = GSM_MI_TYPE_TMSI,
833 .mi_str = "0",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100834 .mi_name = "TMSI-0x00000000",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100835 .expect_mi_tlv_hex = "1705f400000000",
836 .expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
837 },
838 {
839 /* gsm48 treats TMSI as decimal string */
840 .mi_type = GSM_MI_TYPE_TMSI,
841 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100842 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100843 .expect_mi_tlv_hex = "1705f412345678",
844 .str_size = 5,
845 .expect_str = "3054",
846 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns would-be strlen() like snprintf()! */
847 },
848 {
849 .mi_type = GSM_MI_TYPE_NONE,
850 .mi_str = "123",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100851 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200852 .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100853 .expect_str = "",
854 },
855 {
856 .mi_type = GSM_MI_TYPE_NONE,
857 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100858 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200859 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100860 .expect_str = "",
861 },
862 {
863 .mi_type = GSM_MI_ODD,
864 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100865 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200866 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100867 .expect_str = "",
868 },
869};
870
871static void test_mid_encode_decode(void)
872{
873 int i;
874
875 printf("\nTesting Mobile Identity conversions\n");
876
877 for (i = 0; i < ARRAY_SIZE(test_mid_encode_decode_tests); i++) {
878 const struct test_mid_encode_decode_test *t = &test_mid_encode_decode_tests[i];
879 uint8_t tlv_buf[64];
880 uint8_t *mi_buf;
881 int tlv_len;
882 int mi_len;
883 const char *tlv_hex;
884 char str[64] = {};
885 size_t str_size = t->str_size ? : sizeof(str);
886 const char *expect_str = t->expect_str ? : t->mi_str;
887 int expect_rc = t->expect_rc ? : strlen(expect_str)+1;
888 int rc;
889 int str_len;
890
891 printf("- %s %s\n", gsm48_mi_type_name(t->mi_type), t->mi_str);
892 if (t->mi_type == GSM_MI_TYPE_TMSI)
893 tlv_len = gsm48_generate_mid_from_tmsi(tlv_buf, (uint32_t)atoll(t->mi_str));
894 else
895 tlv_len = gsm48_generate_mid(tlv_buf, t->mi_str, t->mi_type);
896 tlv_hex = osmo_hexdump_nospc(tlv_buf, tlv_len);
897
898 printf(" -> MI-TLV-hex='%s'\n", tlv_hex);
899 if (t->expect_mi_tlv_hex && strcmp(tlv_hex, t->expect_mi_tlv_hex)) {
900 printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex);
901 }
902
Harald Weltea13fb752020-06-16 08:44:42 +0200903 /* skip the GSM48_IE_MOBILE_ID tag and length */
904 mi_buf = tlv_buf + 2;
905 mi_len = tlv_len - 2;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100906
907 rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
908 printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc);
909 if (strcmp(str, expect_str))
910 printf(" ERROR: expected MI-str=%s\n", osmo_quote_str(expect_str, -1));
911 if (rc != expect_rc)
912 printf(" ERROR: expected rc=%d\n", expect_rc);
913
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100914 if (t->mi_name) {
915 const char *mi_name = osmo_mi_name(mi_buf, mi_len);
916 printf(" -> MI-name=%s\n", osmo_quote_str(mi_name, -1));
917 if (strcmp(mi_name, t->mi_name))
918 printf(" ERROR: expected MI-name=%s\n", osmo_quote_str(t->mi_name, -1));
919 }
920
Neels Hofmeyr49686282018-12-05 21:32:21 +0100921 /* Now make sure the resulting string is always '\0' terminated.
922 * The above started out with a zeroed buffer, now repeat with a tainted one. */
923 str_len = strlen(str);
924 str[str_len] = '!';
925 gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
926 if (strlen(str) != str_len)
927 printf(" ERROR: resulting string is not explicitly nul terminated\n");
928 }
929}
930
931static const uint8_t test_mid_decode_zero_length_types[] = { GSM_MI_TYPE_IMSI, GSM_MI_TYPE_TMSI, GSM_MI_TYPE_NONE };
932
933static void test_mid_decode_zero_length(void)
934{
935 int odd;
936 uint8_t valid_mi[64];
937 int valid_mi_len;
938
939 printf("\nDecoding zero length Mobile Identities\n");
940
941 /* IMSI = 123456789012345 */
942 valid_mi_len = osmo_hexparse("1932547698103254", valid_mi, sizeof(valid_mi));
943
944 for (odd = 0; odd <= 1; odd++) {
945 int i;
946 for (i = 0; i < ARRAY_SIZE(test_mid_decode_zero_length_types); i++) {
947 uint8_t mi_type = test_mid_decode_zero_length_types[i] | (odd ? GSM_MI_ODD : 0);
948 char str[8] = {};
949 int rc;
950
951 printf("- MI type: %s%s\n", gsm48_mi_type_name(mi_type & GSM_MI_TYPE_MASK),
952 odd ? " | GSM_MI_ODD":"");
953 valid_mi[0] = (valid_mi[0] & 0xf0) | mi_type;
954
955 printf(" - writing to zero-length string:\n");
956 memset(str, '!', sizeof(str) - 1);
957 rc = gsm48_mi_to_string(str, 0, valid_mi, valid_mi_len);
958 printf(" rc=%d\n", rc);
959 if (str[0] == '!')
960 printf(" nothing written\n");
961 else
962 printf(" ERROR: Wrote to invalid memory!\n");
963
964 printf(" - writing to 1-byte-length string:\n");
965 memset(str, '!', sizeof(str) - 1);
966 rc = gsm48_mi_to_string(str, 1, valid_mi, valid_mi_len);
967 printf(" rc=%d\n", rc);
968 if (str[0] == '\0')
969 printf(" returned empty string\n");
970 else if (str[0] == '!')
971 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
972 else
973 printf(" ERROR: Wrote unexpected string %s\n", osmo_quote_str(str, 5));
974 if (str[1] != '!')
975 printf(" ERROR: Wrote to invalid memory!\n");
976
977 printf(" - decode zero-length mi:\n");
978 memset(str, '!', sizeof(str) - 1);
979 rc = gsm48_mi_to_string(str, sizeof(str), valid_mi, 0);
980 printf(" rc=%d\n", rc);
981 if (str[0] == '\0')
982 printf(" returned empty string\n");
983 else if (str[0] == '!')
984 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
985 else
986 printf(" ERROR: expected empty string, got output string: %s\n", osmo_quote_str(str, -1));
987 }
988 }
989 printf("\n");
990}
991
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200992struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex)
993{
994 struct msgb *msg = msgb_alloc_headroom(size, 4, label);
995 OSMO_ASSERT(msg);
996 msg->l3h = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
997 return msg;
998}
999
1000struct mobile_identity_tc {
1001 const char *label;
1002 const char *compl_l3_msg;
1003 int expect_rc;
1004 struct osmo_mobile_identity expect_mi;
1005};
1006
1007/* Some Complete Layer 3 messages copied from real GSM network traces. */
1008struct mobile_identity_tc mobile_identity_tests[] = {
1009 {
1010 .label = "LU with IMSI 901700000004620",
1011 .compl_l3_msg = "050802008168000130" "089910070000006402",
1012 .expect_mi = {
1013 .type = GSM_MI_TYPE_IMSI,
1014 .imsi = "901700000004620",
1015 },
1016 },
1017 {
1018 .label = "LU with TMSI 0x0980ad8a",
1019 .compl_l3_msg = "05084262f224002a50" "05f40980ad8a",
1020 .expect_mi = {
1021 .type = GSM_MI_TYPE_TMSI,
1022 .tmsi = 0x0980ad8a,
1023 },
1024 },
1025 {
1026 .label = "LU with invalid MI type",
1027 .compl_l3_msg = "050802008168000130" "089d10070000006402",
1028 .expect_rc = -EINVAL,
1029 },
1030 {
1031 .label = "LU with truncated IMSI MI",
1032 .compl_l3_msg = "050802008168000130" "0899100700000064",
1033 .expect_rc = -EBADMSG,
1034 },
1035 {
1036 .label = "LU with too short IMSI MI (12345)",
1037 .compl_l3_msg = "050802008168000130" "03193254",
1038 .expect_rc = -EBADMSG,
1039 },
1040 {
1041 .label = "LU with just long enough IMSI MI 123456",
1042 .compl_l3_msg = "050802008168000130" "04113254f6",
1043 .expect_mi = {
1044 .type = GSM_MI_TYPE_IMSI,
1045 .imsi = "123456",
1046 },
1047 },
1048 {
1049 .label = "LU with max length IMSI MI 123456789012345",
1050 .compl_l3_msg = "050802008168000130" "081932547698103254",
1051 .expect_mi = {
1052 .type = GSM_MI_TYPE_IMSI,
1053 .imsi = "123456789012345",
1054 },
1055 },
1056 {
1057 .label = "LU with just too long IMSI MI 1234567890123456",
1058 .compl_l3_msg = "050802008168000130" "091132547698103254f6",
1059 .expect_rc = -EBADMSG,
1060 },
1061 {
1062 .label = "LU with truncated TMSI MI",
1063 .compl_l3_msg = "05084262f224002a50" "05f40980ad",
1064 .expect_rc = -EBADMSG,
1065 },
1066 {
1067 .label = "LU with odd length TMSI",
1068 .compl_l3_msg = "05084262f224002a50" "05fc0980ad8a",
1069 .expect_rc = -EBADMSG,
1070 },
1071 {
1072 .label = "LU with too long TMSI MI",
1073 .compl_l3_msg = "05084262f224002a50" "06f40980ad23",
1074 .expect_rc = -EBADMSG,
1075 },
1076 {
1077 .label = "LU with too short TMSI",
1078 .compl_l3_msg = "05084262f224002a50" "04f480ad8a",
1079 .expect_rc = -EBADMSG,
1080 },
1081 {
1082 .label = "CM Service Request with IMSI 123456",
1083 .compl_l3_msg = "052401035058a6" "04113254f6",
1084 .expect_mi = {
1085 .type = GSM_MI_TYPE_IMSI,
1086 .imsi = "123456",
1087 },
1088 },
1089 {
1090 .label = "CM Service Request with TMSI 0x5a42e404",
1091 .compl_l3_msg = "052401035058a6" "05f45a42e404",
1092 .expect_mi = {
1093 .type = GSM_MI_TYPE_TMSI,
1094 .tmsi = 0x5a42e404,
1095 },
1096 },
1097 {
1098 .label = "CM Service Request with shorter CM2, with IMSI 123456",
1099 .compl_l3_msg = "052401025058" "04113254f6",
1100 .expect_mi = {
1101 .type = GSM_MI_TYPE_IMSI,
1102 .imsi = "123456",
1103 },
1104 },
1105 {
1106 .label = "CM Service Request with longer CM2, with IMSI 123456",
1107 .compl_l3_msg = "052401055058a62342" "04113254f6",
1108 .expect_mi = {
1109 .type = GSM_MI_TYPE_IMSI,
1110 .imsi = "123456",
1111 },
1112 },
1113 {
1114 .label = "CM Service Request with shorter CM2, with TMSI 0x00000000",
1115 .compl_l3_msg = "052401025058" "05f400000000",
1116 .expect_mi = {
1117 .type = GSM_MI_TYPE_TMSI,
1118 .tmsi = 0,
1119 },
1120 },
1121 {
1122 .label = "CM Service Request with invalid MI type",
1123 .compl_l3_msg = "052401035058a6" "089d10070000006402",
1124 .expect_rc = -EINVAL,
1125 },
1126 {
1127 .label = "CM Service Request with truncated IMSI MI",
1128 .compl_l3_msg = "052401035058a6" "0899100700000064",
1129 .expect_rc = -EBADMSG,
1130 },
1131 {
1132 .label = "CM Service Request with truncated TMSI MI",
1133 .compl_l3_msg = "0524010150" "05f40980ad",
1134 .expect_rc = -EBADMSG,
1135 },
1136 {
1137 .label = "CM Service Request with odd length TMSI",
1138 .compl_l3_msg = "052401045058a623" "05fc0980ad8a",
1139 .expect_rc = -EBADMSG,
1140 },
1141 {
1142 .label = "CM Service Request with too long TMSI MI",
1143 .compl_l3_msg = "052401035058a6" "06f40980ad23",
1144 .expect_rc = -EBADMSG,
1145 },
1146 {
1147 .label = "CM Service Request with too short TMSI",
1148 .compl_l3_msg = "052401035058a6" "04f480ad8a",
1149 .expect_rc = -EBADMSG,
1150 },
1151 {
1152 .label = "CM Service Reestablish Request with TMSI 0x5a42e404",
1153 .compl_l3_msg = "052801035058a6" "05f45a42e404",
1154 .expect_mi = {
1155 .type = GSM_MI_TYPE_TMSI,
1156 .tmsi = 0x5a42e404,
1157 },
1158 },
1159 {
1160 .label = "Paging Response with IMSI 1234567",
1161 .compl_l3_msg = "06270003505886" "0419325476",
1162 .expect_mi = {
1163 .type = GSM_MI_TYPE_IMSI,
1164 .imsi = "1234567",
1165 },
1166 },
1167 {
1168 .label = "Paging Response with TMSI 0xb48883de",
1169 .compl_l3_msg = "06270003505886" "05f4b48883de",
1170 .expect_mi = {
1171 .type = GSM_MI_TYPE_TMSI,
1172 .tmsi = 0xb48883de,
1173 },
1174 },
1175 {
1176 .label = "Paging Response with TMSI, with unused nibble not 0xf",
1177 .compl_l3_msg = "06270003505886" "0504b48883de",
1178 .expect_rc = -EBADMSG,
1179 },
1180 {
1181 .label = "Paging Response with too short IMEI (1234567)",
1182 .compl_l3_msg = "06270003505886" "041a325476",
1183 .expect_rc = -EBADMSG,
1184 },
1185 {
1186 .label = "Paging Response with IMEI 123456789012345",
1187 .compl_l3_msg = "06270003505886" "081a32547698103254",
1188 .expect_mi = {
1189 .type = GSM_MI_TYPE_IMEI,
1190 .imei = "123456789012345",
1191 },
1192 },
1193 {
1194 .label = "Paging Response with IMEI 12345678901234 (no Luhn checksum)",
1195 .compl_l3_msg = "06270003505886" "0812325476981032f4",
1196 .expect_mi = {
1197 .type = GSM_MI_TYPE_IMEI,
1198 .imei = "12345678901234",
1199 },
1200 },
1201 {
1202 .label = "Paging Response with IMEISV 1234567890123456",
1203 .compl_l3_msg = "06270003505886" "091332547698103254f6",
1204 .expect_mi = {
1205 .type = GSM_MI_TYPE_IMEISV,
1206 .imeisv = "1234567890123456",
1207 },
1208 },
1209 {
1210 .label = "Paging Response with too short IMEISV 123456789012345",
1211 .compl_l3_msg = "06270003505886" "081b32547698103254",
1212 .expect_rc = -EBADMSG,
1213 },
1214 {
1215 .label = "Paging Response with too long IMEISV 12345678901234567",
1216 .compl_l3_msg = "06270003505886" "091b3254769810325476",
1217 .expect_rc = -EBADMSG,
1218 },
1219 {
1220 .label = "Paging Response with IMSI 123456789012345 and flipped ODD bit",
1221 .compl_l3_msg = "06270003505886" "081132547698103254",
1222 .expect_rc = -EBADMSG,
1223 },
1224 {
1225 .label = "IMSI-Detach with IMSI 901700000004620",
1226 .compl_l3_msg = "050130" "089910070000006402",
1227 .expect_mi = {
1228 .type = GSM_MI_TYPE_IMSI,
1229 .imsi = "901700000004620",
1230 },
1231 },
1232 {
1233 .label = "IMSI-Detach with TMSI 0x0980ad8a",
1234 .compl_l3_msg = "050130" "05f40980ad8a",
1235 .expect_mi = {
1236 .type = GSM_MI_TYPE_TMSI,
1237 .tmsi = 0x0980ad8a,
1238 },
1239 },
1240 {
1241 .label = "IMSI-Detach with invalid MI type",
1242 .compl_l3_msg = "050130" "089d10070000006402",
1243 .expect_rc = -EINVAL,
1244 },
1245 {
1246 .label = "IMSI-Detach with truncated IMSI MI",
1247 .compl_l3_msg = "050130" "0899100700000064",
1248 .expect_rc = -EBADMSG,
1249 },
1250 {
1251 .label = "IMSI-Detach with too short IMSI MI (12345)",
1252 .compl_l3_msg = "050130" "03193254",
1253 .expect_rc = -EBADMSG,
1254 },
1255 {
1256 .label = "IMSI-Detach with just long enough IMSI MI 123456",
1257 .compl_l3_msg = "050130" "04113254f6",
1258 .expect_mi = {
1259 .type = GSM_MI_TYPE_IMSI,
1260 .imsi = "123456",
1261 },
1262 },
1263 {
1264 .label = "IMSI-Detach with max length IMSI MI 123456789012345",
1265 .compl_l3_msg = "050130" "081932547698103254",
1266 .expect_mi = {
1267 .type = GSM_MI_TYPE_IMSI,
1268 .imsi = "123456789012345",
1269 },
1270 },
1271 {
1272 .label = "IMSI-Detach with just too long IMSI MI 1234567890123456",
1273 .compl_l3_msg = "050130" "091132547698103254f6",
1274 .expect_rc = -EBADMSG,
1275 },
1276 {
1277 .label = "IMSI-Detach with truncated TMSI MI",
1278 .compl_l3_msg = "050130" "05f40980ad",
1279 .expect_rc = -EBADMSG,
1280 },
1281 {
1282 .label = "IMSI-Detach with odd length TMSI",
1283 .compl_l3_msg = "050130" "05fc0980ad8a",
1284 .expect_rc = -EBADMSG,
1285 },
1286 {
1287 .label = "IMSI-Detach with too long TMSI MI",
1288 .compl_l3_msg = "050130" "06f40980ad23",
1289 .expect_rc = -EBADMSG,
1290 },
1291 {
1292 .label = "IMSI-Detach with too short TMSI",
1293 .compl_l3_msg = "050130" "04f480ad8a",
1294 .expect_rc = -EBADMSG,
1295 },
1296 {
1297 .label = "Identity Response with IMSI 901700000004620",
1298 .compl_l3_msg = "0519" "089910070000006402",
1299 .expect_mi = {
1300 .type = GSM_MI_TYPE_IMSI,
1301 .imsi = "901700000004620",
1302 },
1303 },
1304 {
1305 .label = "Identity Response with IMEI 123456789012345",
1306 .compl_l3_msg = "0519" "081a32547698103254",
1307 .expect_mi = {
1308 .type = GSM_MI_TYPE_IMEI,
1309 .imei = "123456789012345",
1310 },
1311 },
1312 {
1313 .label = "Identity Response with IMEISV 9876543210987654",
1314 .compl_l3_msg = "0519" "099378563412907856f4",
1315 .expect_mi = {
1316 .type = GSM_MI_TYPE_IMEISV,
1317 .imeisv = "9876543210987654",
1318 },
1319 },
1320};
1321
Harald Weltee61d4592022-11-03 11:05:58 +01001322void test_struct_mobile_identity(void)
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001323{
1324 struct mobile_identity_tc *t;
1325 printf("%s()\n", __func__);
1326 for (t = mobile_identity_tests; (t - mobile_identity_tests) < ARRAY_SIZE(mobile_identity_tests); t++) {
1327 struct osmo_mobile_identity mi;
1328 struct msgb *msg;
1329 int rc;
1330 memset(&mi, 0xff, sizeof(mi));
1331
1332 msg = msgb_from_hex(t->label, 1024, t->compl_l3_msg);
1333 rc = osmo_mobile_identity_decode_from_l3(&mi, msg, false);
1334 msgb_free(msg);
1335
Neels Hofmeyra7f97b92022-08-23 18:35:40 +02001336 printf("%s: %s", t->label, rc ? "rc != 0" : "rc == 0");
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001337 if (!rc) {
1338 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
1339 }
1340
1341 if (rc == t->expect_rc
1342 && ((rc != 0) || !osmo_mobile_identity_cmp(&mi, &t->expect_mi))) {
1343 printf(" ok");
1344 } else {
Neels Hofmeyra7f97b92022-08-23 18:35:40 +02001345 printf(" ERROR: Got rc = %d, expected rc = %d", rc, t->expect_rc);
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001346 if (!t->expect_rc)
1347 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &t->expect_mi));
1348 }
1349 printf("\n");
1350 }
1351 printf("\n");
1352}
1353
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001354static const struct bcd_number_test {
1355 /* Human-readable test name */
1356 const char *test_name;
1357
1358 /* To be encoded number in ASCII */
1359 const char *enc_ascii;
1360 /* Expected encoding result in HEX */
1361 const char *enc_hex;
1362 /* Optional header length (LHV) */
1363 uint8_t enc_h_len;
1364 /* Expected return code */
1365 int enc_rc;
1366
1367 /* To be decoded buffer in HEX */
1368 const char *dec_hex;
1369 /* Expected decoding result in ASCII */
1370 const char *dec_ascii;
1371 /* Optional header length (LHV) */
1372 uint8_t dec_h_len;
1373 /* Expected return code */
1374 int dec_rc;
1375
1376 /* Encoding buffer limit (0 means unlimited) */
1377 size_t enc_buf_lim;
1378 /* Decoding buffer limit (0 means unlimited) */
1379 size_t dec_buf_lim;
1380} bcd_number_test_set[] = {
1381 {
1382 .test_name = "regular 9-digit MSISDN",
1383
1384 /* Encoding test */
1385 .enc_ascii = "123456789",
1386 .enc_hex = "0521436587f9",
1387 .enc_rc = 6,
1388
1389 /* Decoding test */
1390 .dec_hex = "0521436587f9",
1391 .dec_ascii = "123456789",
1392 },
1393 {
1394 .test_name = "regular 6-digit MSISDN with optional header (LHV)",
1395
1396 /* Encoding test */
1397 .enc_ascii = "123456",
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001398 .enc_hex = "07ffffffff214365",
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001399 .enc_h_len = 4, /* LHV */
1400 .enc_rc = 4 + 4,
1401
1402 /* Decoding test */
1403 .dec_hex = "07deadbeef214365",
1404 .dec_ascii = "123456",
1405 .dec_h_len = 4, /* LHV */
1406 },
1407 {
1408 .test_name = "long 15-digit (maximum) MSISDN",
1409
1410 /* Encoding test */
1411 .enc_ascii = "123456789012345",
1412 .enc_hex = "0821436587092143f5",
1413 .enc_rc = 9,
1414
1415 /* Decoding test */
1416 .dec_hex = "0821436587092143f5",
1417 .dec_ascii = "123456789012345",
1418 },
1419 {
1420 .test_name = "long 15-digit (maximum) MSISDN, limited buffer",
1421
1422 /* Encoding test */
1423 .enc_ascii = "123456789012345",
1424 .enc_hex = "0821436587092143f5",
1425 .enc_rc = 9,
1426
1427 /* Decoding test */
1428 .dec_hex = "0821436587092143f5",
1429 .dec_ascii = "123456789012345",
1430
1431 /* Buffer length limitations */
1432 .dec_buf_lim = 15 + 1,
1433 .enc_buf_lim = 9,
1434 },
1435 {
1436 .test_name = "to be truncated 20-digit MSISDN",
1437
1438 /* Encoding test (not enough room in buffer) */
1439 .enc_ascii = "12345678901234567890",
1440 .enc_hex = "", /* nothing */
1441 .enc_rc = -EIO,
1442
1443 /* Decoding test (one 5 digits do not fit) */
1444 .dec_hex = "0a21436587092143658709",
1445 .dec_ascii = "123456789012345",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001446 .dec_rc = -ENOSPC,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001447
1448 /* Buffer length limitations */
1449 .dec_buf_lim = 15 + 1, /* 5 digits less */
1450 .enc_buf_lim = 9,
1451 },
1452 {
1453 .test_name = "LV incorrect length",
1454 .dec_hex = "05214365", /* should be 0x03 */
1455 .dec_ascii = "(none)",
Vadim Yanitskiye4799f52019-05-26 00:55:20 +07001456 .dec_rc = -EINVAL,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001457 },
1458 {
1459 .test_name = "empty input buffer",
1460
1461 /* Encoding test */
1462 .enc_ascii = "",
1463 .enc_hex = "00",
1464 .enc_rc = 1,
1465
1466 /* Decoding test */
1467 .dec_hex = "",
1468 .dec_ascii = "(none)",
1469 .dec_rc = -EIO,
1470 },
Oliver Smith186f8782019-06-06 16:11:32 +02001471 {
1472 .test_name = "decoding buffer is one byte too small (OS#4049)",
1473
1474 /* Decoding test */
1475 .dec_hex = "022143", /* "1234" */
1476 .dec_ascii = "123", /* '4' was truncated */
1477 .dec_rc = -ENOSPC,
1478
1479 /* Buffer length limitations */
1480 .dec_buf_lim = 4,
1481 },
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001482};
1483
Harald Weltee61d4592022-11-03 11:05:58 +01001484static void test_bcd_number_encode_decode(void)
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001485{
1486 const struct bcd_number_test *test;
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001487 uint8_t buf_enc[0xff] = { 0xff };
1488 char buf_dec[0xff] = { 0xff };
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001489 size_t buf_len, i;
1490 int rc;
1491
1492 printf("BSD number encoding / decoding test\n");
1493
1494 for (i = 0; i < ARRAY_SIZE(bcd_number_test_set); i++) {
1495 test = &bcd_number_test_set[i];
1496 printf("- Running test: %s\n", test->test_name);
1497
1498 if (test->enc_ascii) {
1499 if (test->enc_buf_lim)
1500 buf_len = test->enc_buf_lim;
1501 else
1502 buf_len = sizeof(buf_enc);
1503
1504 printf(" - Encoding ASCII (buffer limit=%zu) '%s'...\n",
1505 test->enc_buf_lim, test->enc_ascii);
1506
1507 rc = gsm48_encode_bcd_number(buf_enc, buf_len,
1508 test->enc_h_len, test->enc_ascii);
1509 printf(" - Expected: (rc=%d) '%s'\n",
1510 test->enc_rc, test->enc_hex);
1511 printf(" - Actual: (rc=%d) '%s'\n",
1512 rc, osmo_hexdump_nospc(buf_enc, rc >= 0 ? rc : 0));
1513 }
1514
1515 if (test->dec_hex) {
1516 /* Parse a HEX string */
1517 rc = osmo_hexparse(test->dec_hex, buf_enc, sizeof(buf_enc));
1518 OSMO_ASSERT(rc >= 0);
1519
1520 if (test->dec_buf_lim)
1521 buf_len = test->dec_buf_lim;
1522 else
1523 buf_len = sizeof(buf_dec);
1524
1525 printf(" - Decoding HEX (buffer limit=%zu) '%s'...\n",
1526 test->dec_buf_lim, test->dec_hex);
1527
1528 rc = gsm48_decode_bcd_number2(buf_dec, buf_len,
1529 buf_enc, rc, test->dec_h_len);
1530 printf(" - Expected: (rc=%d) '%s'\n",
1531 test->dec_rc, test->dec_ascii);
1532 printf(" - Actual: (rc=%d) '%s'\n",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001533 rc, (rc == 0 || rc == -ENOSPC) ? buf_dec : "(none)");
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001534 }
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001535
1536 /* Poison buffers between the test iterations */
1537 memset(buf_enc, 0xff, sizeof(buf_enc));
1538 memset(buf_dec, 0xff, sizeof(buf_dec));
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001539 }
1540
1541 printf("\n");
1542}
1543
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001544struct {
1545 int range;
1546 int arfcns_num;
1547 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1548} arfcn_test_ranges[] = {
1549 {OSMO_GSM48_ARFCN_RANGE_512, 12,
1550 { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }},
1551 {OSMO_GSM48_ARFCN_RANGE_512, 17,
1552 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }},
1553 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1554 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }},
1555 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1556 { 1, 17, 31, 45, 58, 79, 81, 97,
1557 113, 127, 213, 277, 287, 311, 331, 391,
1558 417, 511 }},
1559 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1560 { 1, 17, 31, 45, 58, 79 }},
1561 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1562 { 10, 17, 31, 45, 58, 79 }},
1563 {OSMO_GSM48_ARFCN_RANGE_1024, 17,
1564 { 0, 17, 31, 45, 58, 79, 81, 97,
1565 113, 127, 213, 277, 287, 311, 331, 391,
1566 1023 }},
1567 {OSMO_GSM48_ARFCN_RANGE_1024, 16,
1568 { 17, 31, 45, 58, 79, 81, 97, 113,
1569 127, 213, 277, 287, 311, 331, 391, 1023 }},
1570 {-1}
1571};
1572
1573static int test_single_range_encoding(int range, const int *orig_arfcns, int arfcns_num, int silent)
1574{
1575 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1576 int w[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1577 int f0_included = 0;
1578 int rc, f0;
1579 uint8_t chan_list[16] = {0};
1580 struct gsm_sysinfo_freq dec_freq[1024] = {{0}};
1581 int dec_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1582 int dec_arfcns_count = 0;
1583 int arfcns_used = 0;
1584 int i;
1585
1586 arfcns_used = arfcns_num;
1587 memmove(arfcns, orig_arfcns, sizeof(arfcns));
1588
1589 f0 = range == OSMO_GSM48_ARFCN_RANGE_1024 ? 0 : arfcns[0];
1590 /*
1591 * Manipulate the ARFCN list according to the rules in J4 depending
1592 * on the selected range.
1593 */
1594 arfcns_used = osmo_gsm48_range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included);
1595
1596 memset(w, 0, sizeof(w));
1597 osmo_gsm48_range_enc_arfcns(range, arfcns, arfcns_used, w, 0);
1598
1599 if (!silent)
1600 printf("range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", range, arfcns_used, f0, f0_included);
1601
1602 /* Select the range and the amount of bits needed */
1603 switch (range) {
1604 case OSMO_GSM48_ARFCN_RANGE_128:
1605 osmo_gsm48_range_enc_128(chan_list, f0, w);
1606 break;
1607 case OSMO_GSM48_ARFCN_RANGE_256:
1608 osmo_gsm48_range_enc_256(chan_list, f0, w);
1609 break;
1610 case OSMO_GSM48_ARFCN_RANGE_512:
1611 osmo_gsm48_range_enc_512(chan_list, f0, w);
1612 break;
1613 case OSMO_GSM48_ARFCN_RANGE_1024:
1614 osmo_gsm48_range_enc_1024(chan_list, f0, f0_included, w);
1615 break;
1616 default:
1617 return 1;
1618 };
1619
1620 if (!silent)
1621 printf("chan_list = %s\n",
1622 osmo_hexdump(chan_list, sizeof(chan_list)));
1623
1624 rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list),
1625 0xfe, 1);
1626 if (rc != 0) {
1627 printf("Cannot decode freq list, rc = %d\n", rc);
1628 return 1;
1629 }
1630
1631 for (i = 0; i < ARRAY_SIZE(dec_freq); i++) {
1632 if (dec_freq[i].mask &&
1633 dec_arfcns_count < ARRAY_SIZE(dec_arfcns))
1634 dec_arfcns[dec_arfcns_count++] = i;
1635 }
1636
1637 if (!silent) {
1638 printf("Decoded freqs %d (expected %d)\n",
1639 dec_arfcns_count, arfcns_num);
1640 printf("Decoded: ");
1641 for (i = 0; i < dec_arfcns_count; i++) {
1642 printf("%d ", dec_arfcns[i]);
1643 if (dec_arfcns[i] != orig_arfcns[i])
1644 printf("(!= %d) ", orig_arfcns[i]);
1645 }
1646 printf("\n");
1647 }
1648
1649 if (dec_arfcns_count != arfcns_num) {
1650 printf("Wrong number of arfcns\n");
1651 return 1;
1652 }
1653
1654 if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) {
1655 printf("Decoding error, got wrong freqs\n");
1656 printf(" w = ");
1657 for (i = 0; i < ARRAY_SIZE(w); i++)
1658 printf("%d ", w[i]);
1659 printf("\n");
1660 return 1;
1661 }
1662
1663 return 0;
1664}
1665
1666static void test_random_range_encoding(int range, int max_arfcn_num)
1667{
1668 int arfcns_num = 0;
1669 int test_idx;
1670 int rc, max_count;
1671 int num_tests = 1024;
1672
1673 printf("Random range test: range %d, max num ARFCNs %d\n",
1674 range, max_arfcn_num);
1675
1676 srandom(1);
1677
1678 for (max_count = 1; max_count < max_arfcn_num; max_count++) {
1679 for (test_idx = 0; test_idx < num_tests; test_idx++) {
1680 int count;
1681 int i;
1682 int min_freq = 0;
1683
1684 int rnd_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1685 char rnd_arfcns_set[1024] = {0};
1686
1687 if (range < OSMO_GSM48_ARFCN_RANGE_1024)
1688 min_freq = random() % (1023 - range);
1689
1690 for (count = max_count; count; ) {
1691 int arfcn = min_freq + random() % (range + 1);
1692 OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set));
1693
1694 if (!rnd_arfcns_set[arfcn]) {
1695 rnd_arfcns_set[arfcn] = 1;
1696 count -= 1;
1697 }
1698 }
1699
1700 arfcns_num = 0;
1701 for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++)
1702 if (rnd_arfcns_set[i])
1703 rnd_arfcns[arfcns_num++] = i;
1704
1705 rc = test_single_range_encoding(range, rnd_arfcns,
1706 arfcns_num, 1);
1707 if (rc != 0) {
1708 printf("Failed on test %d, range %d, num ARFCNs %d\n",
1709 test_idx, range, max_count);
1710 test_single_range_encoding(range, rnd_arfcns,
1711 arfcns_num, 0);
1712 return;
1713 }
1714 }
1715 }
1716}
1717
Harald Weltee61d4592022-11-03 11:05:58 +01001718static void test_range_encoding(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001719{
1720 int *arfcns;
1721 int arfcns_num = 0;
1722 int test_idx;
1723 int range;
1724
1725 for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++)
1726 {
1727 arfcns_num = arfcn_test_ranges[test_idx].arfcns_num;
1728 arfcns = &arfcn_test_ranges[test_idx].arfcns[0];
1729 range = arfcn_test_ranges[test_idx].range;
1730
1731 printf("Range test %d: range %d, num ARFCNs %d\n",
1732 test_idx, range, arfcns_num);
1733
1734 test_single_range_encoding(range, arfcns, arfcns_num, 0);
1735 }
1736
1737 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_128, 29);
1738 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_256, 22);
1739 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_512, 18);
1740 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_1024, 16);
1741}
1742
1743static int freqs1[] = {
1744 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980
1745};
1746
1747static int freqs2[] = {
1748 402, 460, 1, 67, 131, 197, 272, 347,
1749};
1750
1751static int freqs3[] = {
1752 68, 128, 198, 279, 353, 398, 452,
1753
1754};
1755
1756static int w_out[] = {
1757 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9,
1758};
1759
1760static int range128[] = {
1761 1, 1 + 127,
1762};
1763
1764static int range256[] = {
1765 1, 1 + 128,
1766};
1767
1768static int range512[] = {
1769 1, 1+ 511,
1770};
1771
1772
1773#define VERIFY(res, cmp, wanted) \
1774 if (!(res cmp wanted)) { \
1775 printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
1776 __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \
1777 }
1778
Harald Weltee61d4592022-11-03 11:05:58 +01001779static void test_arfcn_filter(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001780{
1781 int arfcns[50], i, res, f0_included;
1782 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1783 arfcns[i] = (i + 1) * 2;
1784
1785 /* check that the arfcn is taken out. f0_included is only set for Range1024 */
1786 f0_included = 24;
1787 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included);
1788 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1789 VERIFY(f0_included, ==, 1);
1790 for (i = 0; i < res; ++i)
1791 VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1));
1792
1793 /* check with range1024, ARFCN 0 is included */
1794 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1795 arfcns[i] = i * 2;
1796 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1797 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1798 VERIFY(f0_included, ==, 1);
1799 for (i = 0; i < res; ++i)
1800 VERIFY(arfcns[i], ==, (i + 1) * 2 - 1);
1801
1802 /* check with range1024, ARFCN 0 not included */
1803 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1804 arfcns[i] = (i + 1) * 2;
1805 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1806 VERIFY(res, ==, ARRAY_SIZE(arfcns));
1807 VERIFY(f0_included, ==, 0);
1808 for (i = 0; i < res; ++i)
1809 VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1);
1810}
1811
Harald Weltee61d4592022-11-03 11:05:58 +01001812static void test_print_encoding(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001813{
1814 int rc;
1815 int w[17];
1816 uint8_t chan_list[16];
1817 memset(chan_list, 0x23, sizeof(chan_list));
1818
1819 for (rc = 0; rc < ARRAY_SIZE(w); ++rc)
1820 switch (rc % 3) {
1821 case 0:
1822 w[rc] = 0xAAAA;
1823 break;
1824 case 1:
1825 w[rc] = 0x5555;
1826 break;
1827 case 2:
1828 w[rc] = 0x9696;
1829 break;
1830 }
1831
1832 osmo_gsm48_range_enc_512(chan_list, (1 << 9) | 0x96, w);
1833
1834 printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list)));
1835}
1836
Harald Weltee61d4592022-11-03 11:05:58 +01001837static void test_si_range_helpers(void)
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001838{
1839 int ws[(sizeof(freqs1)/sizeof(freqs1[0]))];
1840 int i, f0 = 0xFFFFFF;
1841
1842 memset(&ws[0], 0x23, sizeof(ws));
1843
1844 i = osmo_gsm48_range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1));
1845 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1);
1846 VERIFY(i, ==, 2);
1847
1848 i = osmo_gsm48_range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2));
1849 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1);
1850 VERIFY(i, ==, 2);
1851
1852 i = osmo_gsm48_range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3));
1853 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1);
1854 VERIFY(i, ==, 0);
1855
1856 osmo_gsm48_range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0);
1857
1858 for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) {
1859 printf("w[%d]=%d\n", i, ws[i]);
1860 VERIFY(ws[i], ==, w_out[i]);
1861 }
1862
1863 i = osmo_gsm48_range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0);
1864 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_128);
1865 VERIFY(f0, ==, 1);
1866
1867 i = osmo_gsm48_range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0);
1868 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_256);
1869 VERIFY(f0, ==, 1);
1870
1871 i = osmo_gsm48_range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0);
1872 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_512);
1873 VERIFY(f0, ==, 1);
1874}
1875
Harald Weltee61d4592022-11-03 11:05:58 +01001876static void test_power_ctrl(void)
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001877{
1878 int8_t rc8;
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001879 int rc;
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001880
1881 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_850, 0x00);
1882 VERIFY(rc8, ==, 1);
1883 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x02);
1884 VERIFY(rc8, ==, 3);
1885 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1800, 0x02);
1886 VERIFY(rc8, ==, 3);
1887 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x02);
1888 VERIFY(rc8, ==, 3);
1889 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x04);
1890 VERIFY(rc8, <, 0);
1891 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x04);
1892 VERIFY(rc8, ==, 5);
1893 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x05);
1894 VERIFY(rc8, <, 0);
1895 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0xf2);
1896 VERIFY(rc8, <, 0);
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001897
1898 rc = ms_class_gmsk_dbm(GSM_BAND_850, 0);
1899 VERIFY(rc, <, 0);
1900 rc = ms_class_gmsk_dbm(GSM_BAND_850, 1);
1901 VERIFY(rc, ==, 43);
1902 rc = ms_class_gmsk_dbm(GSM_BAND_900, 3);
1903 VERIFY(rc, ==, 37);
1904 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 2);
1905 VERIFY(rc, ==, 24);
1906 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 3);
1907 VERIFY(rc, ==, 36);
1908 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 3);
1909 VERIFY(rc, ==, 33);
1910 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 4);
1911 VERIFY(rc, <, 0);
1912 rc = ms_class_gmsk_dbm(GSM_BAND_900, 5);
1913 VERIFY(rc, ==, 29);
1914 rc = ms_class_gmsk_dbm(GSM_BAND_900, 6);
1915 VERIFY(rc, <, 0);
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001916}
1917
Harald Weltee61d4592022-11-03 11:05:58 +01001918static void test_rach_tx_integer_raw2val(void)
Pau Espin Pedrol1dac8752022-04-26 17:32:33 +02001919{
1920 unsigned int raw;
1921 for (raw = 0; raw <= 0x0f; raw++) {
1922 unsigned int val = rach_tx_integer_raw2val(raw);
1923 printf("rach_tx_integer_raw2val(0x0%x): %u slots used to spread transmission\n",
1924 raw, val);
1925 }
1926}
1927
Philipp Maierb6a38362023-01-12 12:52:57 +01001928static void test_gsm_gsmtime2fn(void)
1929{
1930 struct gsm_time gsm_time;
1931 uint32_t fn;
1932 uint32_t fn_recovered;
1933
1934 for (fn = 0; fn < 42432; fn++) {
1935 gsm_time.t1 = (fn / 1326) % 32;
1936 gsm_time.t2 = fn % 26;
1937 gsm_time.t3 = fn % 51;
1938
1939 fn_recovered = gsm_gsmtime2fn(&gsm_time);
1940
1941 if (fn_recovered != fn) {
1942 printf(" Wrong frame number computed! t1=%d, t2=%d, t3=%d ==> fn=%d, expected fn=%d\n",
1943 gsm_time.t1, gsm_time.t2, gsm_time.t3, fn_recovered, fn);
1944 OSMO_ASSERT(false);
1945 }
1946 }
1947}
1948
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +02001949static void test_gsm_rfn2fn(void)
1950{
1951 unsigned int i;
1952 struct {
1953 uint32_t curr_fn;
1954 uint16_t rfn;
1955 uint32_t exp_fn;
1956 } input[] = {
1957 { .curr_fn = 0, .rfn = 0, .exp_fn = 0 },
1958 { .curr_fn = 0, .rfn = 4, .exp_fn = 4 },
1959 { .curr_fn = 2229729, .rfn = 23322, .exp_fn = 2229786 },
1960 { .curr_fn = 2229777, .rfn = 23322, .exp_fn = 2229786 },
1961 { .curr_fn = 1320458, .rfn = 5070, .exp_fn = 1320462 },
1962 };
1963
1964 for (i = 0; i < ARRAY_SIZE(input); i++) {
1965 uint32_t fn = gsm_rfn2fn(input[i].rfn, input[i].curr_fn);
1966 if (fn != input[i].exp_fn) {
1967 printf("Wrong frame number computed! curr_fn=%u, rfn=%u ==> fn=%u, expected fn=%u\n",
1968 input[i].curr_fn, input[i].rfn, fn, input[i].exp_fn);
1969 OSMO_ASSERT(false);
1970 }
1971 }
1972}
1973
Harald Weltec8a0b932012-08-24 21:27:26 +02001974int main(int argc, char **argv)
1975{
1976 test_bearer_cap();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001977 test_mid_from_tmsi();
Maxd55d7d42018-02-15 11:27:18 +01001978 test_mid_from_imsi();
Neels Hofmeyr49686282018-12-05 21:32:21 +01001979 test_mid_encode_decode();
1980 test_mid_decode_zero_length();
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001981 test_struct_mobile_identity();
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001982 test_bcd_number_encode_decode();
Max99377c22017-08-30 19:17:50 +02001983 test_ra_cap();
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +01001984 test_lai_encode_decode();
Neels Hofmeyr8d423942023-06-08 00:35:41 +02001985 test_osmo_routing_area_id();
Philipp Maiere36be562020-11-12 11:33:54 +01001986 test_decode_classmark3();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001987
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001988 test_si_range_helpers();
1989 test_arfcn_filter();
1990 test_print_encoding();
1991 test_range_encoding();
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001992 test_power_ctrl();
Pau Espin Pedrol1dac8752022-04-26 17:32:33 +02001993 test_rach_tx_integer_raw2val();
Philipp Maierb6a38362023-01-12 12:52:57 +01001994 test_gsm_gsmtime2fn();
Pau Espin Pedrolaea78a22023-08-11 20:33:38 +02001995 test_gsm_rfn2fn();
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001996
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001997 return EXIT_SUCCESS;
Harald Weltec8a0b932012-08-24 21:27:26 +02001998}