blob: 6fef186139143f5e2479973fc5c8200afa117138 [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 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21#include <string.h>
22#include <stdio.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020023#include <stdlib.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020024
25#include <osmocom/gsm/protocol/gsm_04_08.h>
26#include <osmocom/gsm/gsm48_ie.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020027#include <osmocom/gsm/gsm48.h>
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +020028#include <osmocom/gsm/gsm48_arfcn_range_encode.h>
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +010029#include <osmocom/gsm/gsm_utils.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020030#include <osmocom/gsm/mncc.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020031#include <osmocom/core/backtrace.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020032#include <osmocom/core/utils.h>
33#include <osmocom/core/msgb.h>
34
35
36static const uint8_t csd_9600_v110_lv[] = { 0x07, 0xa1, 0xb8, 0x89, 0x21, 0x15, 0x63, 0x80 };
37
38static const struct gsm_mncc_bearer_cap bcap_csd_9600_v110 = {
39 .transfer = GSM48_BCAP_ITCAP_UNR_DIG_INF,
40 .mode = GSM48_BCAP_TMOD_CIRCUIT,
41 .coding = GSM48_BCAP_CODING_GSM_STD,
42 .radio = GSM48_BCAP_RRQ_FR_ONLY,
43 .speech_ver[0]= -1,
44 .data = {
45 .rate_adaption = GSM48_BCAP_RA_V110_X30,
46 .sig_access = GSM48_BCAP_SA_I440_I450,
47 .async = 1,
48 .nr_stop_bits = 1,
49 .nr_data_bits = 8,
50 .user_rate = GSM48_BCAP_UR_9600,
51 .parity = GSM48_BCAP_PAR_NONE,
52 .interm_rate = GSM48_BCAP_IR_16k,
53 .transp = GSM48_BCAP_TR_TRANSP,
54 .modem_type = GSM48_BCAP_MT_NONE,
55 },
56};
57
58static const uint8_t speech_all_lv[] = { 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81 };
59
60static const struct gsm_mncc_bearer_cap bcap_speech_all = {
61 .transfer = GSM48_BCAP_ITCAP_SPEECH,
62 .mode = GSM48_BCAP_TMOD_CIRCUIT,
63 .coding = GSM48_BCAP_CODING_GSM_STD,
64 .radio = GSM48_BCAP_RRQ_DUAL_FR,
65 .speech_ver = {
66 4, 2, 0, 5, 1, -1,
67 },
68};
69
70
71struct bcap_test {
72 const uint8_t *lv;
73 const struct gsm_mncc_bearer_cap *bc;
74 const char *name;
75};
76
77static const struct bcap_test bcap_tests[] = {
78 { csd_9600_v110_lv, &bcap_csd_9600_v110, "CSD 9600/V.110/transparent" },
79 { speech_all_lv, &bcap_speech_all, "Speech, all codecs" },
80};
81
82static int test_bearer_cap()
83{
84 struct gsm_mncc_bearer_cap bc;
85 int i, rc;
86
87 for (i = 0; i < ARRAY_SIZE(bcap_tests); i++) {
88 struct msgb *msg = msgb_alloc(100, "test");
89 int lv_len;
90
91 memset(&bc, 0, sizeof(bc));
92
93 /* test decoding */
94 rc = gsm48_decode_bearer_cap(&bc, bcap_tests[i].lv);
95 if (rc < 0) {
96 fprintf(stderr, "Error decoding %s\n",
97 bcap_tests[i].name);
98 return rc;
99 }
100 if (memcmp(&bc, bcap_tests[i].bc, sizeof(bc))) {
101 fprintf(stderr, "Incorrect decoded result of %s:\n",
102 bcap_tests[i].name);
103 fprintf(stderr, " should: %s\n",
104 osmo_hexdump((uint8_t *) bcap_tests[i].bc, sizeof(bc)));
105 fprintf(stderr, " is: %s\n",
106 osmo_hexdump((uint8_t *) &bc, sizeof(bc)));
107 return -1;
108 }
109
110 /* also test re-encode? */
111 rc = gsm48_encode_bearer_cap(msg, 1, &bc);
112 if (rc < 0) {
113 fprintf(stderr, "Error encoding %s\n",
114 bcap_tests[i].name);
115 return rc;
116 }
117 lv_len = bcap_tests[i].lv[0]+1;
118 if (memcmp(msg->data, bcap_tests[i].lv, lv_len)) {
119 fprintf(stderr, "Incorrect encoded result of %s:\n",
120 bcap_tests[i].name);
121 fprintf(stderr, " should: %s\n",
122 osmo_hexdump(bcap_tests[i].lv, lv_len));
123 fprintf(stderr, " is: %s\n",
124 osmo_hexdump(msg->data, msg->len));
125 return -1;
126 }
127
128 printf("Test `%s' passed\n", bcap_tests[i].name);
129 msgb_free(msg);
130 }
131
132 return 0;
133}
134
Max99377c22017-08-30 19:17:50 +0200135static inline void dump_ra(const struct gprs_ra_id *raid)
136{
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100137 printf("%s%s\n", osmo_rai_name(raid), raid->mnc_3_digits ? " (3-digit MNC)" : "");
Max99377c22017-08-30 19:17:50 +0200138}
139
140static inline void check_ra(const struct gprs_ra_id *raid)
141{
Maxf1ad60e2018-01-05 14:19:33 +0100142 struct gsm48_ra_id ra;
Max99377c22017-08-30 19:17:50 +0200143 struct gprs_ra_id raid0 = {
144 .mnc = 0,
145 .mcc = 0,
146 .lac = 0,
147 .rac = 0,
148 };
149
Maxf1ad60e2018-01-05 14:19:33 +0100150 gsm48_encode_ra(&ra, raid);
151 printf("Constructed RA:\n");
Max99377c22017-08-30 19:17:50 +0200152
Maxf1ad60e2018-01-05 14:19:33 +0100153 gsm48_parse_ra(&raid0, (const uint8_t *)&ra);
Max99377c22017-08-30 19:17:50 +0200154 dump_ra(raid);
Neels Hofmeyrc38b32d2018-02-20 15:13:18 +0100155 printf("MCC+MNC in BCD: %s\n", osmo_hexdump(ra.digits, sizeof(ra.digits)));
Max99377c22017-08-30 19:17:50 +0200156 dump_ra(&raid0);
157 printf("RA test...");
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100158 if (raid->mnc != raid0.mnc || raid->mcc != raid0.mcc || raid->lac != raid0.lac || raid->rac != raid0.rac
159 || (raid->mnc_3_digits || raid->mnc > 99) != raid0.mnc_3_digits)
Max99377c22017-08-30 19:17:50 +0200160 printf("FAIL\n");
161 else
162 printf("passed\n");
163}
164
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100165static inline void check_lai(const struct gprs_ra_id *raid)
166{
167 int rc;
168 struct gsm48_loc_area_id lai = {};
169 struct gprs_ra_id decoded = {};
170 struct gprs_ra_id _laid = *raid;
171 struct gprs_ra_id *laid = &_laid;
172 laid->rac = 0;
173
174 printf("- gsm48_generate_lai() from "); dump_ra(laid);
175
176 gsm48_generate_lai(&lai, laid->mcc, laid->mnc, laid->lac);
177 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
178 rc = gsm48_decode_lai(&lai, &decoded.mcc, &decoded.mnc, &decoded.lac);
179 if (rc) {
180 printf(" gsm48_decode_lai() returned %d --> FAIL\n", rc);
181 return;
182 }
183 printf(" gsm48_decode_lai() gives "); dump_ra(&decoded);
184 if (decoded.mcc == laid->mcc
185 && decoded.mnc == laid->mnc
186 && decoded.lac == laid->lac)
187 printf(" passed\n");
188 else
189 printf(" FAIL\n");
190}
191
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100192static inline void dump_lai(const struct osmo_location_area_id *lai)
193{
194 printf("%s%s\n", osmo_lai_name(lai), lai->plmn.mnc_3_digits ? " (3-digit MNC)" : "");
195}
196
197static inline void check_lai2(const struct gprs_ra_id *raid)
198{
199 struct gsm48_loc_area_id lai = {};
200 struct osmo_location_area_id decoded = {};
201 struct osmo_location_area_id laid = {
202 .plmn = {
203 .mcc = raid->mcc,
204 .mnc = raid->mnc,
205 .mnc_3_digits = raid->mnc_3_digits,
206 },
207 .lac = raid->lac,
208 };
209
210 printf("- gsm48_generate_lai2() from "); dump_lai(&laid);
211
212 gsm48_generate_lai2(&lai, &laid);
213 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
214 gsm48_decode_lai2(&lai, &decoded);
215 printf(" gsm48_decode_lai2() gives "); dump_lai(&decoded);
216 if (decoded.plmn.mcc == laid.plmn.mcc
217 && decoded.plmn.mnc == laid.plmn.mnc
218 && decoded.lac == laid.lac
219 && decoded.plmn.mnc_3_digits == (laid.plmn.mnc_3_digits || laid.plmn.mnc > 99))
220 printf(" passed\n");
221 else
222 printf(" FAIL\n");
223}
224
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100225static struct gprs_ra_id test_ra_cap_items[] = {
226 {
Max99377c22017-08-30 19:17:50 +0200227 .mcc = 77,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100228 .mnc = 121,
Max99377c22017-08-30 19:17:50 +0200229 .lac = 666,
230 .rac = 5,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100231 },
232 {
Max99377c22017-08-30 19:17:50 +0200233 .mcc = 84,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100234 .mnc = 98,
Max99377c22017-08-30 19:17:50 +0200235 .lac = 11,
236 .rac = 89,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100237 },
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100238 {
239 .mcc = 0,
240 .mnc = 0,
241 .lac = 0,
242 .rac = 0,
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100243 .mnc_3_digits = false,
244 /* expecting 000-00, BCD = 00 f0 00 */
245 },
246 {
247 .mcc = 0,
248 .mnc = 0,
249 .lac = 0,
250 .rac = 0,
251 .mnc_3_digits = true,
252 /* expecting 000-000, BCD = 00 00 00 */
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100253 },
254 {
255 .mcc = 999,
256 .mnc = 999,
257 .lac = 65535,
258 .rac = 255,
259 },
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100260 {
261 .mcc = 1,
262 .mnc = 2,
263 .lac = 23,
264 .rac = 42,
265 .mnc_3_digits = false,
266 /* expecting 001-02, BCD = 00 f1 20 */
267 },
268 {
269 .mcc = 1,
270 .mnc = 2,
271 .lac = 23,
272 .rac = 42,
273 .mnc_3_digits = true,
274 /* expecting 001-002, BCD = 00 21 00 */
275 },
276 {
277 .mcc = 12,
278 .mnc = 34,
279 .lac = 56,
280 .rac = 78,
281 .mnc_3_digits = false,
282 /* expecting 012-34, BCD = 10 f2 43 */
283 },
284 {
285 .mcc = 12,
286 .mnc = 34,
287 .lac = 23,
288 .rac = 42,
289 .mnc_3_digits = true,
290 /* expecting 012-034, BCD = 10 42 30 */
291 },
292 {
293 .mcc = 123,
294 .mnc = 456,
295 .lac = 23,
296 .rac = 42,
297 .mnc_3_digits = false,
298 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
299 },
300 {
301 .mcc = 123,
302 .mnc = 456,
303 .lac = 23,
304 .rac = 42,
305 .mnc_3_digits = true,
306 /* expecting 123-456, BCD = 21 63 54 (same) */
307 },
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100308};
Max99377c22017-08-30 19:17:50 +0200309
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100310static void test_ra_cap(void)
311{
312 int i;
313
314 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++)
315 check_ra(&test_ra_cap_items[i]);
Max99377c22017-08-30 19:17:50 +0200316}
317
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100318static void test_lai_encode_decode(void)
319{
320 int i;
321
322 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++) {
323 check_lai(&test_ra_cap_items[i]);
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100324 check_lai2(&test_ra_cap_items[i]);
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100325 }
326}
327
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200328static void test_mid_from_tmsi(void)
329{
330 static const uint8_t res[] = { 0x17, 0x05, 0xf4, 0xaa, 0xbb, 0xcc, 0xdd };
331
332
333 uint32_t tmsi = 0xAABBCCDD;
334 uint8_t buf[3 + sizeof(uint32_t)];
335
336 printf("Simple TMSI encoding test....");
337
338 memset(&buf, 0xFE, sizeof(buf));
339 gsm48_generate_mid_from_tmsi(buf, tmsi);
340
341 OSMO_ASSERT(memcmp(buf, res, sizeof(res)) == 0);
342 printf("passed\n");
343}
344
Maxd55d7d42018-02-15 11:27:18 +0100345static void test_mid_from_imsi(void)
346{
347 char *imsi = "901700000004620";
348 uint8_t buf[10], len;
349
350 printf("Simple IMSI encoding test....");
351
352 len = gsm48_generate_mid_from_imsi(buf, imsi);
353
354 printf("passed: [%u] %s\n", len, osmo_hexdump(buf, len));
355}
356
Neels Hofmeyr49686282018-12-05 21:32:21 +0100357struct test_mid_encode_decode_test {
358 uint8_t mi_type;
359 const char *mi_str;
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100360 const char *mi_name;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100361 size_t str_size;
362 const char *expect_mi_tlv_hex;
363 const char *expect_str;
364 int expect_rc;
365};
366
367static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = {
368 {
369 .mi_type = GSM_MI_TYPE_IMSI,
370 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100371 .mi_name = "IMSI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100372 .expect_mi_tlv_hex = "17081932547698103254",
373 },
374 {
375 .mi_type = GSM_MI_TYPE_IMSI,
376 .mi_str = "12345678901234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100377 .mi_name = "IMSI-12345678901234",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100378 .expect_mi_tlv_hex = "170811325476981032f4",
379 },
380 {
381 .mi_type = GSM_MI_TYPE_IMSI,
382 .mi_str = "423423",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100383 .mi_name = "IMSI-423423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100384 .expect_mi_tlv_hex = "1704413224f3",
385 },
386 {
387 .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD,
388 .mi_str = "423423",
Harald Weltea13fb752020-06-16 08:44:42 +0200389 .mi_name = "IMSI-423423",
390 .expect_mi_tlv_hex = "1704413224f3",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100391 },
392 {
393 .mi_type = GSM_MI_TYPE_IMSI,
394 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100395 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100396 .expect_mi_tlv_hex = "170449322453",
397 },
398 {
399 .mi_type = GSM_MI_TYPE_IMSI,
400 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100401 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100402 .expect_mi_tlv_hex = "170449322453",
403 .str_size = 4,
404 .expect_str = "423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100405 },
406 {
407 .mi_type = GSM_MI_TYPE_IMEI,
408 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100409 .mi_name = "IMEI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100410 .expect_mi_tlv_hex = "17081a32547698103254",
411 },
412 {
413 .mi_type = GSM_MI_TYPE_IMEI,
414 .mi_str = "98765432109876",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100415 .mi_name = "IMEI-98765432109876",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100416 .expect_mi_tlv_hex = "170892785634129078f6",
417 },
418 {
419 .mi_type = GSM_MI_TYPE_IMEI,
420 .mi_str = "987654321098765",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100421 .mi_name = "IMEI-987654321098765",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100422 .expect_mi_tlv_hex = "17089a78563412907856",
423 },
424 {
425 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100426 .mi_str = "9876543210987654",
427 .mi_name = "IMEI-SV-9876543210987654",
428 .expect_mi_tlv_hex = "17099378563412907856f4",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100429 },
430 {
431 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100432 .mi_str = "9876543210987654",
433 .mi_name = "IMEI-SV-9876543210987654",
434 .expect_mi_tlv_hex = "17099378563412907856f4",
435 .str_size = 17,
436 .expect_str = "9876543210987654",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100437 },
438 {
439 /* gsm48 treats TMSI as decimal string */
440 .mi_type = GSM_MI_TYPE_TMSI,
441 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100442 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100443 .expect_mi_tlv_hex = "1705f412345678",
444 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
445 },
446 {
447 .mi_type = GSM_MI_TYPE_TMSI,
448 .mi_str = "12648430", /* 0xc0ffee as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100449 .mi_name = "TMSI-0x00C0FFEE",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100450 .expect_mi_tlv_hex = "1705f400c0ffee",
451 .expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
452 },
453 {
454 .mi_type = GSM_MI_TYPE_TMSI,
455 .mi_str = "0",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100456 .mi_name = "TMSI-0x00000000",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100457 .expect_mi_tlv_hex = "1705f400000000",
458 .expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
459 },
460 {
461 /* gsm48 treats TMSI as decimal string */
462 .mi_type = GSM_MI_TYPE_TMSI,
463 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100464 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100465 .expect_mi_tlv_hex = "1705f412345678",
466 .str_size = 5,
467 .expect_str = "3054",
468 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns would-be strlen() like snprintf()! */
469 },
470 {
471 .mi_type = GSM_MI_TYPE_NONE,
472 .mi_str = "123",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100473 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200474 .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100475 .expect_str = "",
476 },
477 {
478 .mi_type = GSM_MI_TYPE_NONE,
479 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100480 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200481 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100482 .expect_str = "",
483 },
484 {
485 .mi_type = GSM_MI_ODD,
486 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100487 .mi_name = "unknown",
Harald Weltea13fb752020-06-16 08:44:42 +0200488 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100489 .expect_str = "",
490 },
491};
492
493static void test_mid_encode_decode(void)
494{
495 int i;
496
497 printf("\nTesting Mobile Identity conversions\n");
498
499 for (i = 0; i < ARRAY_SIZE(test_mid_encode_decode_tests); i++) {
500 const struct test_mid_encode_decode_test *t = &test_mid_encode_decode_tests[i];
501 uint8_t tlv_buf[64];
502 uint8_t *mi_buf;
503 int tlv_len;
504 int mi_len;
505 const char *tlv_hex;
506 char str[64] = {};
507 size_t str_size = t->str_size ? : sizeof(str);
508 const char *expect_str = t->expect_str ? : t->mi_str;
509 int expect_rc = t->expect_rc ? : strlen(expect_str)+1;
510 int rc;
511 int str_len;
512
513 printf("- %s %s\n", gsm48_mi_type_name(t->mi_type), t->mi_str);
514 if (t->mi_type == GSM_MI_TYPE_TMSI)
515 tlv_len = gsm48_generate_mid_from_tmsi(tlv_buf, (uint32_t)atoll(t->mi_str));
516 else
517 tlv_len = gsm48_generate_mid(tlv_buf, t->mi_str, t->mi_type);
518 tlv_hex = osmo_hexdump_nospc(tlv_buf, tlv_len);
519
520 printf(" -> MI-TLV-hex='%s'\n", tlv_hex);
521 if (t->expect_mi_tlv_hex && strcmp(tlv_hex, t->expect_mi_tlv_hex)) {
522 printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex);
523 }
524
Harald Weltea13fb752020-06-16 08:44:42 +0200525 /* skip the GSM48_IE_MOBILE_ID tag and length */
526 mi_buf = tlv_buf + 2;
527 mi_len = tlv_len - 2;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100528
529 rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
530 printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc);
531 if (strcmp(str, expect_str))
532 printf(" ERROR: expected MI-str=%s\n", osmo_quote_str(expect_str, -1));
533 if (rc != expect_rc)
534 printf(" ERROR: expected rc=%d\n", expect_rc);
535
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100536 if (t->mi_name) {
537 const char *mi_name = osmo_mi_name(mi_buf, mi_len);
538 printf(" -> MI-name=%s\n", osmo_quote_str(mi_name, -1));
539 if (strcmp(mi_name, t->mi_name))
540 printf(" ERROR: expected MI-name=%s\n", osmo_quote_str(t->mi_name, -1));
541 }
542
Neels Hofmeyr49686282018-12-05 21:32:21 +0100543 /* Now make sure the resulting string is always '\0' terminated.
544 * The above started out with a zeroed buffer, now repeat with a tainted one. */
545 str_len = strlen(str);
546 str[str_len] = '!';
547 gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
548 if (strlen(str) != str_len)
549 printf(" ERROR: resulting string is not explicitly nul terminated\n");
550 }
551}
552
553static const uint8_t test_mid_decode_zero_length_types[] = { GSM_MI_TYPE_IMSI, GSM_MI_TYPE_TMSI, GSM_MI_TYPE_NONE };
554
555static void test_mid_decode_zero_length(void)
556{
557 int odd;
558 uint8_t valid_mi[64];
559 int valid_mi_len;
560
561 printf("\nDecoding zero length Mobile Identities\n");
562
563 /* IMSI = 123456789012345 */
564 valid_mi_len = osmo_hexparse("1932547698103254", valid_mi, sizeof(valid_mi));
565
566 for (odd = 0; odd <= 1; odd++) {
567 int i;
568 for (i = 0; i < ARRAY_SIZE(test_mid_decode_zero_length_types); i++) {
569 uint8_t mi_type = test_mid_decode_zero_length_types[i] | (odd ? GSM_MI_ODD : 0);
570 char str[8] = {};
571 int rc;
572
573 printf("- MI type: %s%s\n", gsm48_mi_type_name(mi_type & GSM_MI_TYPE_MASK),
574 odd ? " | GSM_MI_ODD":"");
575 valid_mi[0] = (valid_mi[0] & 0xf0) | mi_type;
576
577 printf(" - writing to zero-length string:\n");
578 memset(str, '!', sizeof(str) - 1);
579 rc = gsm48_mi_to_string(str, 0, valid_mi, valid_mi_len);
580 printf(" rc=%d\n", rc);
581 if (str[0] == '!')
582 printf(" nothing written\n");
583 else
584 printf(" ERROR: Wrote to invalid memory!\n");
585
586 printf(" - writing to 1-byte-length string:\n");
587 memset(str, '!', sizeof(str) - 1);
588 rc = gsm48_mi_to_string(str, 1, valid_mi, valid_mi_len);
589 printf(" rc=%d\n", rc);
590 if (str[0] == '\0')
591 printf(" returned empty string\n");
592 else if (str[0] == '!')
593 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
594 else
595 printf(" ERROR: Wrote unexpected string %s\n", osmo_quote_str(str, 5));
596 if (str[1] != '!')
597 printf(" ERROR: Wrote to invalid memory!\n");
598
599 printf(" - decode zero-length mi:\n");
600 memset(str, '!', sizeof(str) - 1);
601 rc = gsm48_mi_to_string(str, sizeof(str), valid_mi, 0);
602 printf(" rc=%d\n", rc);
603 if (str[0] == '\0')
604 printf(" returned empty string\n");
605 else if (str[0] == '!')
606 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
607 else
608 printf(" ERROR: expected empty string, got output string: %s\n", osmo_quote_str(str, -1));
609 }
610 }
611 printf("\n");
612}
613
Neels Hofmeyr83025bf2020-05-26 02:45:23 +0200614struct msgb *msgb_from_hex(const char *label, uint16_t size, const char *hex)
615{
616 struct msgb *msg = msgb_alloc_headroom(size, 4, label);
617 OSMO_ASSERT(msg);
618 msg->l3h = msgb_put(msg, osmo_hexparse(hex, msg->data, msgb_tailroom(msg)));
619 return msg;
620}
621
622struct mobile_identity_tc {
623 const char *label;
624 const char *compl_l3_msg;
625 int expect_rc;
626 struct osmo_mobile_identity expect_mi;
627};
628
629/* Some Complete Layer 3 messages copied from real GSM network traces. */
630struct mobile_identity_tc mobile_identity_tests[] = {
631 {
632 .label = "LU with IMSI 901700000004620",
633 .compl_l3_msg = "050802008168000130" "089910070000006402",
634 .expect_mi = {
635 .type = GSM_MI_TYPE_IMSI,
636 .imsi = "901700000004620",
637 },
638 },
639 {
640 .label = "LU with TMSI 0x0980ad8a",
641 .compl_l3_msg = "05084262f224002a50" "05f40980ad8a",
642 .expect_mi = {
643 .type = GSM_MI_TYPE_TMSI,
644 .tmsi = 0x0980ad8a,
645 },
646 },
647 {
648 .label = "LU with invalid MI type",
649 .compl_l3_msg = "050802008168000130" "089d10070000006402",
650 .expect_rc = -EINVAL,
651 },
652 {
653 .label = "LU with truncated IMSI MI",
654 .compl_l3_msg = "050802008168000130" "0899100700000064",
655 .expect_rc = -EBADMSG,
656 },
657 {
658 .label = "LU with too short IMSI MI (12345)",
659 .compl_l3_msg = "050802008168000130" "03193254",
660 .expect_rc = -EBADMSG,
661 },
662 {
663 .label = "LU with just long enough IMSI MI 123456",
664 .compl_l3_msg = "050802008168000130" "04113254f6",
665 .expect_mi = {
666 .type = GSM_MI_TYPE_IMSI,
667 .imsi = "123456",
668 },
669 },
670 {
671 .label = "LU with max length IMSI MI 123456789012345",
672 .compl_l3_msg = "050802008168000130" "081932547698103254",
673 .expect_mi = {
674 .type = GSM_MI_TYPE_IMSI,
675 .imsi = "123456789012345",
676 },
677 },
678 {
679 .label = "LU with just too long IMSI MI 1234567890123456",
680 .compl_l3_msg = "050802008168000130" "091132547698103254f6",
681 .expect_rc = -EBADMSG,
682 },
683 {
684 .label = "LU with truncated TMSI MI",
685 .compl_l3_msg = "05084262f224002a50" "05f40980ad",
686 .expect_rc = -EBADMSG,
687 },
688 {
689 .label = "LU with odd length TMSI",
690 .compl_l3_msg = "05084262f224002a50" "05fc0980ad8a",
691 .expect_rc = -EBADMSG,
692 },
693 {
694 .label = "LU with too long TMSI MI",
695 .compl_l3_msg = "05084262f224002a50" "06f40980ad23",
696 .expect_rc = -EBADMSG,
697 },
698 {
699 .label = "LU with too short TMSI",
700 .compl_l3_msg = "05084262f224002a50" "04f480ad8a",
701 .expect_rc = -EBADMSG,
702 },
703 {
704 .label = "CM Service Request with IMSI 123456",
705 .compl_l3_msg = "052401035058a6" "04113254f6",
706 .expect_mi = {
707 .type = GSM_MI_TYPE_IMSI,
708 .imsi = "123456",
709 },
710 },
711 {
712 .label = "CM Service Request with TMSI 0x5a42e404",
713 .compl_l3_msg = "052401035058a6" "05f45a42e404",
714 .expect_mi = {
715 .type = GSM_MI_TYPE_TMSI,
716 .tmsi = 0x5a42e404,
717 },
718 },
719 {
720 .label = "CM Service Request with shorter CM2, with IMSI 123456",
721 .compl_l3_msg = "052401025058" "04113254f6",
722 .expect_mi = {
723 .type = GSM_MI_TYPE_IMSI,
724 .imsi = "123456",
725 },
726 },
727 {
728 .label = "CM Service Request with longer CM2, with IMSI 123456",
729 .compl_l3_msg = "052401055058a62342" "04113254f6",
730 .expect_mi = {
731 .type = GSM_MI_TYPE_IMSI,
732 .imsi = "123456",
733 },
734 },
735 {
736 .label = "CM Service Request with shorter CM2, with TMSI 0x00000000",
737 .compl_l3_msg = "052401025058" "05f400000000",
738 .expect_mi = {
739 .type = GSM_MI_TYPE_TMSI,
740 .tmsi = 0,
741 },
742 },
743 {
744 .label = "CM Service Request with invalid MI type",
745 .compl_l3_msg = "052401035058a6" "089d10070000006402",
746 .expect_rc = -EINVAL,
747 },
748 {
749 .label = "CM Service Request with truncated IMSI MI",
750 .compl_l3_msg = "052401035058a6" "0899100700000064",
751 .expect_rc = -EBADMSG,
752 },
753 {
754 .label = "CM Service Request with truncated TMSI MI",
755 .compl_l3_msg = "0524010150" "05f40980ad",
756 .expect_rc = -EBADMSG,
757 },
758 {
759 .label = "CM Service Request with odd length TMSI",
760 .compl_l3_msg = "052401045058a623" "05fc0980ad8a",
761 .expect_rc = -EBADMSG,
762 },
763 {
764 .label = "CM Service Request with too long TMSI MI",
765 .compl_l3_msg = "052401035058a6" "06f40980ad23",
766 .expect_rc = -EBADMSG,
767 },
768 {
769 .label = "CM Service Request with too short TMSI",
770 .compl_l3_msg = "052401035058a6" "04f480ad8a",
771 .expect_rc = -EBADMSG,
772 },
773 {
774 .label = "CM Service Reestablish Request with TMSI 0x5a42e404",
775 .compl_l3_msg = "052801035058a6" "05f45a42e404",
776 .expect_mi = {
777 .type = GSM_MI_TYPE_TMSI,
778 .tmsi = 0x5a42e404,
779 },
780 },
781 {
782 .label = "Paging Response with IMSI 1234567",
783 .compl_l3_msg = "06270003505886" "0419325476",
784 .expect_mi = {
785 .type = GSM_MI_TYPE_IMSI,
786 .imsi = "1234567",
787 },
788 },
789 {
790 .label = "Paging Response with TMSI 0xb48883de",
791 .compl_l3_msg = "06270003505886" "05f4b48883de",
792 .expect_mi = {
793 .type = GSM_MI_TYPE_TMSI,
794 .tmsi = 0xb48883de,
795 },
796 },
797 {
798 .label = "Paging Response with TMSI, with unused nibble not 0xf",
799 .compl_l3_msg = "06270003505886" "0504b48883de",
800 .expect_rc = -EBADMSG,
801 },
802 {
803 .label = "Paging Response with too short IMEI (1234567)",
804 .compl_l3_msg = "06270003505886" "041a325476",
805 .expect_rc = -EBADMSG,
806 },
807 {
808 .label = "Paging Response with IMEI 123456789012345",
809 .compl_l3_msg = "06270003505886" "081a32547698103254",
810 .expect_mi = {
811 .type = GSM_MI_TYPE_IMEI,
812 .imei = "123456789012345",
813 },
814 },
815 {
816 .label = "Paging Response with IMEI 12345678901234 (no Luhn checksum)",
817 .compl_l3_msg = "06270003505886" "0812325476981032f4",
818 .expect_mi = {
819 .type = GSM_MI_TYPE_IMEI,
820 .imei = "12345678901234",
821 },
822 },
823 {
824 .label = "Paging Response with IMEISV 1234567890123456",
825 .compl_l3_msg = "06270003505886" "091332547698103254f6",
826 .expect_mi = {
827 .type = GSM_MI_TYPE_IMEISV,
828 .imeisv = "1234567890123456",
829 },
830 },
831 {
832 .label = "Paging Response with too short IMEISV 123456789012345",
833 .compl_l3_msg = "06270003505886" "081b32547698103254",
834 .expect_rc = -EBADMSG,
835 },
836 {
837 .label = "Paging Response with too long IMEISV 12345678901234567",
838 .compl_l3_msg = "06270003505886" "091b3254769810325476",
839 .expect_rc = -EBADMSG,
840 },
841 {
842 .label = "Paging Response with IMSI 123456789012345 and flipped ODD bit",
843 .compl_l3_msg = "06270003505886" "081132547698103254",
844 .expect_rc = -EBADMSG,
845 },
846 {
847 .label = "IMSI-Detach with IMSI 901700000004620",
848 .compl_l3_msg = "050130" "089910070000006402",
849 .expect_mi = {
850 .type = GSM_MI_TYPE_IMSI,
851 .imsi = "901700000004620",
852 },
853 },
854 {
855 .label = "IMSI-Detach with TMSI 0x0980ad8a",
856 .compl_l3_msg = "050130" "05f40980ad8a",
857 .expect_mi = {
858 .type = GSM_MI_TYPE_TMSI,
859 .tmsi = 0x0980ad8a,
860 },
861 },
862 {
863 .label = "IMSI-Detach with invalid MI type",
864 .compl_l3_msg = "050130" "089d10070000006402",
865 .expect_rc = -EINVAL,
866 },
867 {
868 .label = "IMSI-Detach with truncated IMSI MI",
869 .compl_l3_msg = "050130" "0899100700000064",
870 .expect_rc = -EBADMSG,
871 },
872 {
873 .label = "IMSI-Detach with too short IMSI MI (12345)",
874 .compl_l3_msg = "050130" "03193254",
875 .expect_rc = -EBADMSG,
876 },
877 {
878 .label = "IMSI-Detach with just long enough IMSI MI 123456",
879 .compl_l3_msg = "050130" "04113254f6",
880 .expect_mi = {
881 .type = GSM_MI_TYPE_IMSI,
882 .imsi = "123456",
883 },
884 },
885 {
886 .label = "IMSI-Detach with max length IMSI MI 123456789012345",
887 .compl_l3_msg = "050130" "081932547698103254",
888 .expect_mi = {
889 .type = GSM_MI_TYPE_IMSI,
890 .imsi = "123456789012345",
891 },
892 },
893 {
894 .label = "IMSI-Detach with just too long IMSI MI 1234567890123456",
895 .compl_l3_msg = "050130" "091132547698103254f6",
896 .expect_rc = -EBADMSG,
897 },
898 {
899 .label = "IMSI-Detach with truncated TMSI MI",
900 .compl_l3_msg = "050130" "05f40980ad",
901 .expect_rc = -EBADMSG,
902 },
903 {
904 .label = "IMSI-Detach with odd length TMSI",
905 .compl_l3_msg = "050130" "05fc0980ad8a",
906 .expect_rc = -EBADMSG,
907 },
908 {
909 .label = "IMSI-Detach with too long TMSI MI",
910 .compl_l3_msg = "050130" "06f40980ad23",
911 .expect_rc = -EBADMSG,
912 },
913 {
914 .label = "IMSI-Detach with too short TMSI",
915 .compl_l3_msg = "050130" "04f480ad8a",
916 .expect_rc = -EBADMSG,
917 },
918 {
919 .label = "Identity Response with IMSI 901700000004620",
920 .compl_l3_msg = "0519" "089910070000006402",
921 .expect_mi = {
922 .type = GSM_MI_TYPE_IMSI,
923 .imsi = "901700000004620",
924 },
925 },
926 {
927 .label = "Identity Response with IMEI 123456789012345",
928 .compl_l3_msg = "0519" "081a32547698103254",
929 .expect_mi = {
930 .type = GSM_MI_TYPE_IMEI,
931 .imei = "123456789012345",
932 },
933 },
934 {
935 .label = "Identity Response with IMEISV 9876543210987654",
936 .compl_l3_msg = "0519" "099378563412907856f4",
937 .expect_mi = {
938 .type = GSM_MI_TYPE_IMEISV,
939 .imeisv = "9876543210987654",
940 },
941 },
942};
943
944void test_struct_mobile_identity()
945{
946 struct mobile_identity_tc *t;
947 printf("%s()\n", __func__);
948 for (t = mobile_identity_tests; (t - mobile_identity_tests) < ARRAY_SIZE(mobile_identity_tests); t++) {
949 struct osmo_mobile_identity mi;
950 struct msgb *msg;
951 int rc;
952 memset(&mi, 0xff, sizeof(mi));
953
954 msg = msgb_from_hex(t->label, 1024, t->compl_l3_msg);
955 rc = osmo_mobile_identity_decode_from_l3(&mi, msg, false);
956 msgb_free(msg);
957
958 printf("%s: rc = %d", t->label, rc);
959 if (!rc) {
960 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
961 }
962
963 if (rc == t->expect_rc
964 && ((rc != 0) || !osmo_mobile_identity_cmp(&mi, &t->expect_mi))) {
965 printf(" ok");
966 } else {
967 printf(" ERROR: Expected rc = %d", t->expect_rc);
968 if (!t->expect_rc)
969 printf(", mi = %s", osmo_mobile_identity_to_str_c(OTC_SELECT, &t->expect_mi));
970 }
971 printf("\n");
972 }
973 printf("\n");
974}
975
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700976static const struct bcd_number_test {
977 /* Human-readable test name */
978 const char *test_name;
979
980 /* To be encoded number in ASCII */
981 const char *enc_ascii;
982 /* Expected encoding result in HEX */
983 const char *enc_hex;
984 /* Optional header length (LHV) */
985 uint8_t enc_h_len;
986 /* Expected return code */
987 int enc_rc;
988
989 /* To be decoded buffer in HEX */
990 const char *dec_hex;
991 /* Expected decoding result in ASCII */
992 const char *dec_ascii;
993 /* Optional header length (LHV) */
994 uint8_t dec_h_len;
995 /* Expected return code */
996 int dec_rc;
997
998 /* Encoding buffer limit (0 means unlimited) */
999 size_t enc_buf_lim;
1000 /* Decoding buffer limit (0 means unlimited) */
1001 size_t dec_buf_lim;
1002} bcd_number_test_set[] = {
1003 {
1004 .test_name = "regular 9-digit MSISDN",
1005
1006 /* Encoding test */
1007 .enc_ascii = "123456789",
1008 .enc_hex = "0521436587f9",
1009 .enc_rc = 6,
1010
1011 /* Decoding test */
1012 .dec_hex = "0521436587f9",
1013 .dec_ascii = "123456789",
1014 },
1015 {
1016 .test_name = "regular 6-digit MSISDN with optional header (LHV)",
1017
1018 /* Encoding test */
1019 .enc_ascii = "123456",
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001020 .enc_hex = "07ffffffff214365",
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001021 .enc_h_len = 4, /* LHV */
1022 .enc_rc = 4 + 4,
1023
1024 /* Decoding test */
1025 .dec_hex = "07deadbeef214365",
1026 .dec_ascii = "123456",
1027 .dec_h_len = 4, /* LHV */
1028 },
1029 {
1030 .test_name = "long 15-digit (maximum) MSISDN",
1031
1032 /* Encoding test */
1033 .enc_ascii = "123456789012345",
1034 .enc_hex = "0821436587092143f5",
1035 .enc_rc = 9,
1036
1037 /* Decoding test */
1038 .dec_hex = "0821436587092143f5",
1039 .dec_ascii = "123456789012345",
1040 },
1041 {
1042 .test_name = "long 15-digit (maximum) MSISDN, limited buffer",
1043
1044 /* Encoding test */
1045 .enc_ascii = "123456789012345",
1046 .enc_hex = "0821436587092143f5",
1047 .enc_rc = 9,
1048
1049 /* Decoding test */
1050 .dec_hex = "0821436587092143f5",
1051 .dec_ascii = "123456789012345",
1052
1053 /* Buffer length limitations */
1054 .dec_buf_lim = 15 + 1,
1055 .enc_buf_lim = 9,
1056 },
1057 {
1058 .test_name = "to be truncated 20-digit MSISDN",
1059
1060 /* Encoding test (not enough room in buffer) */
1061 .enc_ascii = "12345678901234567890",
1062 .enc_hex = "", /* nothing */
1063 .enc_rc = -EIO,
1064
1065 /* Decoding test (one 5 digits do not fit) */
1066 .dec_hex = "0a21436587092143658709",
1067 .dec_ascii = "123456789012345",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001068 .dec_rc = -ENOSPC,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001069
1070 /* Buffer length limitations */
1071 .dec_buf_lim = 15 + 1, /* 5 digits less */
1072 .enc_buf_lim = 9,
1073 },
1074 {
1075 .test_name = "LV incorrect length",
1076 .dec_hex = "05214365", /* should be 0x03 */
1077 .dec_ascii = "(none)",
Vadim Yanitskiye4799f52019-05-26 00:55:20 +07001078 .dec_rc = -EINVAL,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001079 },
1080 {
1081 .test_name = "empty input buffer",
1082
1083 /* Encoding test */
1084 .enc_ascii = "",
1085 .enc_hex = "00",
1086 .enc_rc = 1,
1087
1088 /* Decoding test */
1089 .dec_hex = "",
1090 .dec_ascii = "(none)",
1091 .dec_rc = -EIO,
1092 },
Oliver Smith186f8782019-06-06 16:11:32 +02001093 {
1094 .test_name = "decoding buffer is one byte too small (OS#4049)",
1095
1096 /* Decoding test */
1097 .dec_hex = "022143", /* "1234" */
1098 .dec_ascii = "123", /* '4' was truncated */
1099 .dec_rc = -ENOSPC,
1100
1101 /* Buffer length limitations */
1102 .dec_buf_lim = 4,
1103 },
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001104};
1105
1106static void test_bcd_number_encode_decode()
1107{
1108 const struct bcd_number_test *test;
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001109 uint8_t buf_enc[0xff] = { 0xff };
1110 char buf_dec[0xff] = { 0xff };
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001111 size_t buf_len, i;
1112 int rc;
1113
1114 printf("BSD number encoding / decoding test\n");
1115
1116 for (i = 0; i < ARRAY_SIZE(bcd_number_test_set); i++) {
1117 test = &bcd_number_test_set[i];
1118 printf("- Running test: %s\n", test->test_name);
1119
1120 if (test->enc_ascii) {
1121 if (test->enc_buf_lim)
1122 buf_len = test->enc_buf_lim;
1123 else
1124 buf_len = sizeof(buf_enc);
1125
1126 printf(" - Encoding ASCII (buffer limit=%zu) '%s'...\n",
1127 test->enc_buf_lim, test->enc_ascii);
1128
1129 rc = gsm48_encode_bcd_number(buf_enc, buf_len,
1130 test->enc_h_len, test->enc_ascii);
1131 printf(" - Expected: (rc=%d) '%s'\n",
1132 test->enc_rc, test->enc_hex);
1133 printf(" - Actual: (rc=%d) '%s'\n",
1134 rc, osmo_hexdump_nospc(buf_enc, rc >= 0 ? rc : 0));
1135 }
1136
1137 if (test->dec_hex) {
1138 /* Parse a HEX string */
1139 rc = osmo_hexparse(test->dec_hex, buf_enc, sizeof(buf_enc));
1140 OSMO_ASSERT(rc >= 0);
1141
1142 if (test->dec_buf_lim)
1143 buf_len = test->dec_buf_lim;
1144 else
1145 buf_len = sizeof(buf_dec);
1146
1147 printf(" - Decoding HEX (buffer limit=%zu) '%s'...\n",
1148 test->dec_buf_lim, test->dec_hex);
1149
1150 rc = gsm48_decode_bcd_number2(buf_dec, buf_len,
1151 buf_enc, rc, test->dec_h_len);
1152 printf(" - Expected: (rc=%d) '%s'\n",
1153 test->dec_rc, test->dec_ascii);
1154 printf(" - Actual: (rc=%d) '%s'\n",
Vadim Yanitskiy71940872019-05-26 00:49:57 +07001155 rc, (rc == 0 || rc == -ENOSPC) ? buf_dec : "(none)");
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001156 }
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +07001157
1158 /* Poison buffers between the test iterations */
1159 memset(buf_enc, 0xff, sizeof(buf_enc));
1160 memset(buf_dec, 0xff, sizeof(buf_dec));
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001161 }
1162
1163 printf("\n");
1164}
1165
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001166struct {
1167 int range;
1168 int arfcns_num;
1169 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1170} arfcn_test_ranges[] = {
1171 {OSMO_GSM48_ARFCN_RANGE_512, 12,
1172 { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }},
1173 {OSMO_GSM48_ARFCN_RANGE_512, 17,
1174 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }},
1175 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1176 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }},
1177 {OSMO_GSM48_ARFCN_RANGE_512, 18,
1178 { 1, 17, 31, 45, 58, 79, 81, 97,
1179 113, 127, 213, 277, 287, 311, 331, 391,
1180 417, 511 }},
1181 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1182 { 1, 17, 31, 45, 58, 79 }},
1183 {OSMO_GSM48_ARFCN_RANGE_512, 6,
1184 { 10, 17, 31, 45, 58, 79 }},
1185 {OSMO_GSM48_ARFCN_RANGE_1024, 17,
1186 { 0, 17, 31, 45, 58, 79, 81, 97,
1187 113, 127, 213, 277, 287, 311, 331, 391,
1188 1023 }},
1189 {OSMO_GSM48_ARFCN_RANGE_1024, 16,
1190 { 17, 31, 45, 58, 79, 81, 97, 113,
1191 127, 213, 277, 287, 311, 331, 391, 1023 }},
1192 {-1}
1193};
1194
1195static int test_single_range_encoding(int range, const int *orig_arfcns, int arfcns_num, int silent)
1196{
1197 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1198 int w[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
1199 int f0_included = 0;
1200 int rc, f0;
1201 uint8_t chan_list[16] = {0};
1202 struct gsm_sysinfo_freq dec_freq[1024] = {{0}};
1203 int dec_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1204 int dec_arfcns_count = 0;
1205 int arfcns_used = 0;
1206 int i;
1207
1208 arfcns_used = arfcns_num;
1209 memmove(arfcns, orig_arfcns, sizeof(arfcns));
1210
1211 f0 = range == OSMO_GSM48_ARFCN_RANGE_1024 ? 0 : arfcns[0];
1212 /*
1213 * Manipulate the ARFCN list according to the rules in J4 depending
1214 * on the selected range.
1215 */
1216 arfcns_used = osmo_gsm48_range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included);
1217
1218 memset(w, 0, sizeof(w));
1219 osmo_gsm48_range_enc_arfcns(range, arfcns, arfcns_used, w, 0);
1220
1221 if (!silent)
1222 printf("range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", range, arfcns_used, f0, f0_included);
1223
1224 /* Select the range and the amount of bits needed */
1225 switch (range) {
1226 case OSMO_GSM48_ARFCN_RANGE_128:
1227 osmo_gsm48_range_enc_128(chan_list, f0, w);
1228 break;
1229 case OSMO_GSM48_ARFCN_RANGE_256:
1230 osmo_gsm48_range_enc_256(chan_list, f0, w);
1231 break;
1232 case OSMO_GSM48_ARFCN_RANGE_512:
1233 osmo_gsm48_range_enc_512(chan_list, f0, w);
1234 break;
1235 case OSMO_GSM48_ARFCN_RANGE_1024:
1236 osmo_gsm48_range_enc_1024(chan_list, f0, f0_included, w);
1237 break;
1238 default:
1239 return 1;
1240 };
1241
1242 if (!silent)
1243 printf("chan_list = %s\n",
1244 osmo_hexdump(chan_list, sizeof(chan_list)));
1245
1246 rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list),
1247 0xfe, 1);
1248 if (rc != 0) {
1249 printf("Cannot decode freq list, rc = %d\n", rc);
1250 return 1;
1251 }
1252
1253 for (i = 0; i < ARRAY_SIZE(dec_freq); i++) {
1254 if (dec_freq[i].mask &&
1255 dec_arfcns_count < ARRAY_SIZE(dec_arfcns))
1256 dec_arfcns[dec_arfcns_count++] = i;
1257 }
1258
1259 if (!silent) {
1260 printf("Decoded freqs %d (expected %d)\n",
1261 dec_arfcns_count, arfcns_num);
1262 printf("Decoded: ");
1263 for (i = 0; i < dec_arfcns_count; i++) {
1264 printf("%d ", dec_arfcns[i]);
1265 if (dec_arfcns[i] != orig_arfcns[i])
1266 printf("(!= %d) ", orig_arfcns[i]);
1267 }
1268 printf("\n");
1269 }
1270
1271 if (dec_arfcns_count != arfcns_num) {
1272 printf("Wrong number of arfcns\n");
1273 return 1;
1274 }
1275
1276 if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) {
1277 printf("Decoding error, got wrong freqs\n");
1278 printf(" w = ");
1279 for (i = 0; i < ARRAY_SIZE(w); i++)
1280 printf("%d ", w[i]);
1281 printf("\n");
1282 return 1;
1283 }
1284
1285 return 0;
1286}
1287
1288static void test_random_range_encoding(int range, int max_arfcn_num)
1289{
1290 int arfcns_num = 0;
1291 int test_idx;
1292 int rc, max_count;
1293 int num_tests = 1024;
1294
1295 printf("Random range test: range %d, max num ARFCNs %d\n",
1296 range, max_arfcn_num);
1297
1298 srandom(1);
1299
1300 for (max_count = 1; max_count < max_arfcn_num; max_count++) {
1301 for (test_idx = 0; test_idx < num_tests; test_idx++) {
1302 int count;
1303 int i;
1304 int min_freq = 0;
1305
1306 int rnd_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
1307 char rnd_arfcns_set[1024] = {0};
1308
1309 if (range < OSMO_GSM48_ARFCN_RANGE_1024)
1310 min_freq = random() % (1023 - range);
1311
1312 for (count = max_count; count; ) {
1313 int arfcn = min_freq + random() % (range + 1);
1314 OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set));
1315
1316 if (!rnd_arfcns_set[arfcn]) {
1317 rnd_arfcns_set[arfcn] = 1;
1318 count -= 1;
1319 }
1320 }
1321
1322 arfcns_num = 0;
1323 for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++)
1324 if (rnd_arfcns_set[i])
1325 rnd_arfcns[arfcns_num++] = i;
1326
1327 rc = test_single_range_encoding(range, rnd_arfcns,
1328 arfcns_num, 1);
1329 if (rc != 0) {
1330 printf("Failed on test %d, range %d, num ARFCNs %d\n",
1331 test_idx, range, max_count);
1332 test_single_range_encoding(range, rnd_arfcns,
1333 arfcns_num, 0);
1334 return;
1335 }
1336 }
1337 }
1338}
1339
1340static void test_range_encoding()
1341{
1342 int *arfcns;
1343 int arfcns_num = 0;
1344 int test_idx;
1345 int range;
1346
1347 for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++)
1348 {
1349 arfcns_num = arfcn_test_ranges[test_idx].arfcns_num;
1350 arfcns = &arfcn_test_ranges[test_idx].arfcns[0];
1351 range = arfcn_test_ranges[test_idx].range;
1352
1353 printf("Range test %d: range %d, num ARFCNs %d\n",
1354 test_idx, range, arfcns_num);
1355
1356 test_single_range_encoding(range, arfcns, arfcns_num, 0);
1357 }
1358
1359 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_128, 29);
1360 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_256, 22);
1361 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_512, 18);
1362 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_1024, 16);
1363}
1364
1365static int freqs1[] = {
1366 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980
1367};
1368
1369static int freqs2[] = {
1370 402, 460, 1, 67, 131, 197, 272, 347,
1371};
1372
1373static int freqs3[] = {
1374 68, 128, 198, 279, 353, 398, 452,
1375
1376};
1377
1378static int w_out[] = {
1379 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9,
1380};
1381
1382static int range128[] = {
1383 1, 1 + 127,
1384};
1385
1386static int range256[] = {
1387 1, 1 + 128,
1388};
1389
1390static int range512[] = {
1391 1, 1+ 511,
1392};
1393
1394
1395#define VERIFY(res, cmp, wanted) \
1396 if (!(res cmp wanted)) { \
1397 printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
1398 __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \
1399 }
1400
1401static void test_arfcn_filter()
1402{
1403 int arfcns[50], i, res, f0_included;
1404 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1405 arfcns[i] = (i + 1) * 2;
1406
1407 /* check that the arfcn is taken out. f0_included is only set for Range1024 */
1408 f0_included = 24;
1409 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included);
1410 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1411 VERIFY(f0_included, ==, 1);
1412 for (i = 0; i < res; ++i)
1413 VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1));
1414
1415 /* check with range1024, ARFCN 0 is included */
1416 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1417 arfcns[i] = i * 2;
1418 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1419 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1420 VERIFY(f0_included, ==, 1);
1421 for (i = 0; i < res; ++i)
1422 VERIFY(arfcns[i], ==, (i + 1) * 2 - 1);
1423
1424 /* check with range1024, ARFCN 0 not included */
1425 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1426 arfcns[i] = (i + 1) * 2;
1427 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1428 VERIFY(res, ==, ARRAY_SIZE(arfcns));
1429 VERIFY(f0_included, ==, 0);
1430 for (i = 0; i < res; ++i)
1431 VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1);
1432}
1433
1434static void test_print_encoding()
1435{
1436 int rc;
1437 int w[17];
1438 uint8_t chan_list[16];
1439 memset(chan_list, 0x23, sizeof(chan_list));
1440
1441 for (rc = 0; rc < ARRAY_SIZE(w); ++rc)
1442 switch (rc % 3) {
1443 case 0:
1444 w[rc] = 0xAAAA;
1445 break;
1446 case 1:
1447 w[rc] = 0x5555;
1448 break;
1449 case 2:
1450 w[rc] = 0x9696;
1451 break;
1452 }
1453
1454 osmo_gsm48_range_enc_512(chan_list, (1 << 9) | 0x96, w);
1455
1456 printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list)));
1457}
1458
1459static void test_si_range_helpers()
1460{
1461 int ws[(sizeof(freqs1)/sizeof(freqs1[0]))];
1462 int i, f0 = 0xFFFFFF;
1463
1464 memset(&ws[0], 0x23, sizeof(ws));
1465
1466 i = osmo_gsm48_range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1));
1467 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1);
1468 VERIFY(i, ==, 2);
1469
1470 i = osmo_gsm48_range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2));
1471 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1);
1472 VERIFY(i, ==, 2);
1473
1474 i = osmo_gsm48_range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3));
1475 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1);
1476 VERIFY(i, ==, 0);
1477
1478 osmo_gsm48_range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0);
1479
1480 for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) {
1481 printf("w[%d]=%d\n", i, ws[i]);
1482 VERIFY(ws[i], ==, w_out[i]);
1483 }
1484
1485 i = osmo_gsm48_range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0);
1486 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_128);
1487 VERIFY(f0, ==, 1);
1488
1489 i = osmo_gsm48_range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0);
1490 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_256);
1491 VERIFY(f0, ==, 1);
1492
1493 i = osmo_gsm48_range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0);
1494 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_512);
1495 VERIFY(f0, ==, 1);
1496}
1497
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001498static void test_power_ctrl()
1499{
1500 int8_t rc8;
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001501 int rc;
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001502
1503 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_850, 0x00);
1504 VERIFY(rc8, ==, 1);
1505 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x02);
1506 VERIFY(rc8, ==, 3);
1507 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1800, 0x02);
1508 VERIFY(rc8, ==, 3);
1509 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x02);
1510 VERIFY(rc8, ==, 3);
1511 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x04);
1512 VERIFY(rc8, <, 0);
1513 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x04);
1514 VERIFY(rc8, ==, 5);
1515 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x05);
1516 VERIFY(rc8, <, 0);
1517 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0xf2);
1518 VERIFY(rc8, <, 0);
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001519
1520 rc = ms_class_gmsk_dbm(GSM_BAND_850, 0);
1521 VERIFY(rc, <, 0);
1522 rc = ms_class_gmsk_dbm(GSM_BAND_850, 1);
1523 VERIFY(rc, ==, 43);
1524 rc = ms_class_gmsk_dbm(GSM_BAND_900, 3);
1525 VERIFY(rc, ==, 37);
1526 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 2);
1527 VERIFY(rc, ==, 24);
1528 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 3);
1529 VERIFY(rc, ==, 36);
1530 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 3);
1531 VERIFY(rc, ==, 33);
1532 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 4);
1533 VERIFY(rc, <, 0);
1534 rc = ms_class_gmsk_dbm(GSM_BAND_900, 5);
1535 VERIFY(rc, ==, 29);
1536 rc = ms_class_gmsk_dbm(GSM_BAND_900, 6);
1537 VERIFY(rc, <, 0);
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001538}
1539
Harald Weltec8a0b932012-08-24 21:27:26 +02001540int main(int argc, char **argv)
1541{
1542 test_bearer_cap();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001543 test_mid_from_tmsi();
Maxd55d7d42018-02-15 11:27:18 +01001544 test_mid_from_imsi();
Neels Hofmeyr49686282018-12-05 21:32:21 +01001545 test_mid_encode_decode();
1546 test_mid_decode_zero_length();
Neels Hofmeyr83025bf2020-05-26 02:45:23 +02001547 test_struct_mobile_identity();
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001548 test_bcd_number_encode_decode();
Max99377c22017-08-30 19:17:50 +02001549 test_ra_cap();
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +01001550 test_lai_encode_decode();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001551
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001552 test_si_range_helpers();
1553 test_arfcn_filter();
1554 test_print_encoding();
1555 test_range_encoding();
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001556 test_power_ctrl();
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001557
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001558 return EXIT_SUCCESS;
Harald Weltec8a0b932012-08-24 21:27:26 +02001559}