blob: 2d60b845789bab0bb82e8bda39a423c3ec2c0251 [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>
Harald Weltec8a0b932012-08-24 21:27:26 +020029#include <osmocom/gsm/mncc.h>
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +020030#include <osmocom/core/backtrace.h>
Harald Weltec8a0b932012-08-24 21:27:26 +020031#include <osmocom/core/utils.h>
32#include <osmocom/core/msgb.h>
33
34
35static const uint8_t csd_9600_v110_lv[] = { 0x07, 0xa1, 0xb8, 0x89, 0x21, 0x15, 0x63, 0x80 };
36
37static const struct gsm_mncc_bearer_cap bcap_csd_9600_v110 = {
38 .transfer = GSM48_BCAP_ITCAP_UNR_DIG_INF,
39 .mode = GSM48_BCAP_TMOD_CIRCUIT,
40 .coding = GSM48_BCAP_CODING_GSM_STD,
41 .radio = GSM48_BCAP_RRQ_FR_ONLY,
42 .speech_ver[0]= -1,
43 .data = {
44 .rate_adaption = GSM48_BCAP_RA_V110_X30,
45 .sig_access = GSM48_BCAP_SA_I440_I450,
46 .async = 1,
47 .nr_stop_bits = 1,
48 .nr_data_bits = 8,
49 .user_rate = GSM48_BCAP_UR_9600,
50 .parity = GSM48_BCAP_PAR_NONE,
51 .interm_rate = GSM48_BCAP_IR_16k,
52 .transp = GSM48_BCAP_TR_TRANSP,
53 .modem_type = GSM48_BCAP_MT_NONE,
54 },
55};
56
57static const uint8_t speech_all_lv[] = { 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81 };
58
59static const struct gsm_mncc_bearer_cap bcap_speech_all = {
60 .transfer = GSM48_BCAP_ITCAP_SPEECH,
61 .mode = GSM48_BCAP_TMOD_CIRCUIT,
62 .coding = GSM48_BCAP_CODING_GSM_STD,
63 .radio = GSM48_BCAP_RRQ_DUAL_FR,
64 .speech_ver = {
65 4, 2, 0, 5, 1, -1,
66 },
67};
68
69
70struct bcap_test {
71 const uint8_t *lv;
72 const struct gsm_mncc_bearer_cap *bc;
73 const char *name;
74};
75
76static const struct bcap_test bcap_tests[] = {
77 { csd_9600_v110_lv, &bcap_csd_9600_v110, "CSD 9600/V.110/transparent" },
78 { speech_all_lv, &bcap_speech_all, "Speech, all codecs" },
79};
80
81static int test_bearer_cap()
82{
83 struct gsm_mncc_bearer_cap bc;
84 int i, rc;
85
86 for (i = 0; i < ARRAY_SIZE(bcap_tests); i++) {
87 struct msgb *msg = msgb_alloc(100, "test");
88 int lv_len;
89
90 memset(&bc, 0, sizeof(bc));
91
92 /* test decoding */
93 rc = gsm48_decode_bearer_cap(&bc, bcap_tests[i].lv);
94 if (rc < 0) {
95 fprintf(stderr, "Error decoding %s\n",
96 bcap_tests[i].name);
97 return rc;
98 }
99 if (memcmp(&bc, bcap_tests[i].bc, sizeof(bc))) {
100 fprintf(stderr, "Incorrect decoded result of %s:\n",
101 bcap_tests[i].name);
102 fprintf(stderr, " should: %s\n",
103 osmo_hexdump((uint8_t *) bcap_tests[i].bc, sizeof(bc)));
104 fprintf(stderr, " is: %s\n",
105 osmo_hexdump((uint8_t *) &bc, sizeof(bc)));
106 return -1;
107 }
108
109 /* also test re-encode? */
110 rc = gsm48_encode_bearer_cap(msg, 1, &bc);
111 if (rc < 0) {
112 fprintf(stderr, "Error encoding %s\n",
113 bcap_tests[i].name);
114 return rc;
115 }
116 lv_len = bcap_tests[i].lv[0]+1;
117 if (memcmp(msg->data, bcap_tests[i].lv, lv_len)) {
118 fprintf(stderr, "Incorrect encoded result of %s:\n",
119 bcap_tests[i].name);
120 fprintf(stderr, " should: %s\n",
121 osmo_hexdump(bcap_tests[i].lv, lv_len));
122 fprintf(stderr, " is: %s\n",
123 osmo_hexdump(msg->data, msg->len));
124 return -1;
125 }
126
127 printf("Test `%s' passed\n", bcap_tests[i].name);
128 msgb_free(msg);
129 }
130
131 return 0;
132}
133
Max99377c22017-08-30 19:17:50 +0200134static inline void dump_ra(const struct gprs_ra_id *raid)
135{
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100136 printf("%s%s\n", osmo_rai_name(raid), raid->mnc_3_digits ? " (3-digit MNC)" : "");
Max99377c22017-08-30 19:17:50 +0200137}
138
139static inline void check_ra(const struct gprs_ra_id *raid)
140{
Maxf1ad60e2018-01-05 14:19:33 +0100141 struct gsm48_ra_id ra;
Max99377c22017-08-30 19:17:50 +0200142 struct gprs_ra_id raid0 = {
143 .mnc = 0,
144 .mcc = 0,
145 .lac = 0,
146 .rac = 0,
147 };
148
Maxf1ad60e2018-01-05 14:19:33 +0100149 gsm48_encode_ra(&ra, raid);
150 printf("Constructed RA:\n");
Max99377c22017-08-30 19:17:50 +0200151
Maxf1ad60e2018-01-05 14:19:33 +0100152 gsm48_parse_ra(&raid0, (const uint8_t *)&ra);
Max99377c22017-08-30 19:17:50 +0200153 dump_ra(raid);
Neels Hofmeyrc38b32d2018-02-20 15:13:18 +0100154 printf("MCC+MNC in BCD: %s\n", osmo_hexdump(ra.digits, sizeof(ra.digits)));
Max99377c22017-08-30 19:17:50 +0200155 dump_ra(&raid0);
156 printf("RA test...");
Neels Hofmeyrdbb25132018-02-20 15:12:23 +0100157 if (raid->mnc != raid0.mnc || raid->mcc != raid0.mcc || raid->lac != raid0.lac || raid->rac != raid0.rac
158 || (raid->mnc_3_digits || raid->mnc > 99) != raid0.mnc_3_digits)
Max99377c22017-08-30 19:17:50 +0200159 printf("FAIL\n");
160 else
161 printf("passed\n");
162}
163
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100164static inline void check_lai(const struct gprs_ra_id *raid)
165{
166 int rc;
167 struct gsm48_loc_area_id lai = {};
168 struct gprs_ra_id decoded = {};
169 struct gprs_ra_id _laid = *raid;
170 struct gprs_ra_id *laid = &_laid;
171 laid->rac = 0;
172
173 printf("- gsm48_generate_lai() from "); dump_ra(laid);
174
175 gsm48_generate_lai(&lai, laid->mcc, laid->mnc, laid->lac);
176 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
177 rc = gsm48_decode_lai(&lai, &decoded.mcc, &decoded.mnc, &decoded.lac);
178 if (rc) {
179 printf(" gsm48_decode_lai() returned %d --> FAIL\n", rc);
180 return;
181 }
182 printf(" gsm48_decode_lai() gives "); dump_ra(&decoded);
183 if (decoded.mcc == laid->mcc
184 && decoded.mnc == laid->mnc
185 && decoded.lac == laid->lac)
186 printf(" passed\n");
187 else
188 printf(" FAIL\n");
189}
190
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100191static inline void dump_lai(const struct osmo_location_area_id *lai)
192{
193 printf("%s%s\n", osmo_lai_name(lai), lai->plmn.mnc_3_digits ? " (3-digit MNC)" : "");
194}
195
196static inline void check_lai2(const struct gprs_ra_id *raid)
197{
198 struct gsm48_loc_area_id lai = {};
199 struct osmo_location_area_id decoded = {};
200 struct osmo_location_area_id laid = {
201 .plmn = {
202 .mcc = raid->mcc,
203 .mnc = raid->mnc,
204 .mnc_3_digits = raid->mnc_3_digits,
205 },
206 .lac = raid->lac,
207 };
208
209 printf("- gsm48_generate_lai2() from "); dump_lai(&laid);
210
211 gsm48_generate_lai2(&lai, &laid);
212 printf(" Encoded %s\n", osmo_hexdump((unsigned char*)&lai, sizeof(lai)));
213 gsm48_decode_lai2(&lai, &decoded);
214 printf(" gsm48_decode_lai2() gives "); dump_lai(&decoded);
215 if (decoded.plmn.mcc == laid.plmn.mcc
216 && decoded.plmn.mnc == laid.plmn.mnc
217 && decoded.lac == laid.lac
218 && decoded.plmn.mnc_3_digits == (laid.plmn.mnc_3_digits || laid.plmn.mnc > 99))
219 printf(" passed\n");
220 else
221 printf(" FAIL\n");
222}
223
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100224static struct gprs_ra_id test_ra_cap_items[] = {
225 {
Max99377c22017-08-30 19:17:50 +0200226 .mcc = 77,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100227 .mnc = 121,
Max99377c22017-08-30 19:17:50 +0200228 .lac = 666,
229 .rac = 5,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100230 },
231 {
Max99377c22017-08-30 19:17:50 +0200232 .mcc = 84,
Neels Hofmeyr0bf93a62018-02-20 22:06:56 +0100233 .mnc = 98,
Max99377c22017-08-30 19:17:50 +0200234 .lac = 11,
235 .rac = 89,
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100236 },
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100237 {
238 .mcc = 0,
239 .mnc = 0,
240 .lac = 0,
241 .rac = 0,
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100242 .mnc_3_digits = false,
243 /* expecting 000-00, BCD = 00 f0 00 */
244 },
245 {
246 .mcc = 0,
247 .mnc = 0,
248 .lac = 0,
249 .rac = 0,
250 .mnc_3_digits = true,
251 /* expecting 000-000, BCD = 00 00 00 */
Neels Hofmeyrb9fd7eb2018-02-20 15:14:03 +0100252 },
253 {
254 .mcc = 999,
255 .mnc = 999,
256 .lac = 65535,
257 .rac = 255,
258 },
Neels Hofmeyr6c7b3e22018-02-20 22:20:42 +0100259 {
260 .mcc = 1,
261 .mnc = 2,
262 .lac = 23,
263 .rac = 42,
264 .mnc_3_digits = false,
265 /* expecting 001-02, BCD = 00 f1 20 */
266 },
267 {
268 .mcc = 1,
269 .mnc = 2,
270 .lac = 23,
271 .rac = 42,
272 .mnc_3_digits = true,
273 /* expecting 001-002, BCD = 00 21 00 */
274 },
275 {
276 .mcc = 12,
277 .mnc = 34,
278 .lac = 56,
279 .rac = 78,
280 .mnc_3_digits = false,
281 /* expecting 012-34, BCD = 10 f2 43 */
282 },
283 {
284 .mcc = 12,
285 .mnc = 34,
286 .lac = 23,
287 .rac = 42,
288 .mnc_3_digits = true,
289 /* expecting 012-034, BCD = 10 42 30 */
290 },
291 {
292 .mcc = 123,
293 .mnc = 456,
294 .lac = 23,
295 .rac = 42,
296 .mnc_3_digits = false,
297 /* expecting 123-456, BCD = 21 63 54 (false flag has no effect) */
298 },
299 {
300 .mcc = 123,
301 .mnc = 456,
302 .lac = 23,
303 .rac = 42,
304 .mnc_3_digits = true,
305 /* expecting 123-456, BCD = 21 63 54 (same) */
306 },
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100307};
Max99377c22017-08-30 19:17:50 +0200308
Neels Hofmeyr22da1452018-02-20 15:11:25 +0100309static void test_ra_cap(void)
310{
311 int i;
312
313 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++)
314 check_ra(&test_ra_cap_items[i]);
Max99377c22017-08-30 19:17:50 +0200315}
316
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100317static void test_lai_encode_decode(void)
318{
319 int i;
320
321 for (i = 0; i < ARRAY_SIZE(test_ra_cap_items); i++) {
322 check_lai(&test_ra_cap_items[i]);
Neels Hofmeyr4566f4e2018-02-20 22:19:56 +0100323 check_lai2(&test_ra_cap_items[i]);
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100324 }
325}
326
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200327static void test_mid_from_tmsi(void)
328{
329 static const uint8_t res[] = { 0x17, 0x05, 0xf4, 0xaa, 0xbb, 0xcc, 0xdd };
330
331
332 uint32_t tmsi = 0xAABBCCDD;
333 uint8_t buf[3 + sizeof(uint32_t)];
334
335 printf("Simple TMSI encoding test....");
336
337 memset(&buf, 0xFE, sizeof(buf));
338 gsm48_generate_mid_from_tmsi(buf, tmsi);
339
340 OSMO_ASSERT(memcmp(buf, res, sizeof(res)) == 0);
341 printf("passed\n");
342}
343
Maxd55d7d42018-02-15 11:27:18 +0100344static void test_mid_from_imsi(void)
345{
346 char *imsi = "901700000004620";
347 uint8_t buf[10], len;
348
349 printf("Simple IMSI encoding test....");
350
351 len = gsm48_generate_mid_from_imsi(buf, imsi);
352
353 printf("passed: [%u] %s\n", len, osmo_hexdump(buf, len));
354}
355
Neels Hofmeyr49686282018-12-05 21:32:21 +0100356struct test_mid_encode_decode_test {
357 uint8_t mi_type;
358 const char *mi_str;
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100359 const char *mi_name;
Neels Hofmeyr49686282018-12-05 21:32:21 +0100360 size_t str_size;
361 const char *expect_mi_tlv_hex;
362 const char *expect_str;
363 int expect_rc;
364};
365
366static const struct test_mid_encode_decode_test test_mid_encode_decode_tests[] = {
367 {
368 .mi_type = GSM_MI_TYPE_IMSI,
369 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100370 .mi_name = "IMSI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100371 .expect_mi_tlv_hex = "17081932547698103254",
372 },
373 {
374 .mi_type = GSM_MI_TYPE_IMSI,
375 .mi_str = "12345678901234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100376 .mi_name = "IMSI-12345678901234",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100377 .expect_mi_tlv_hex = "170811325476981032f4",
378 },
379 {
380 .mi_type = GSM_MI_TYPE_IMSI,
381 .mi_str = "423423",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100382 .mi_name = "IMSI-423423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100383 .expect_mi_tlv_hex = "1704413224f3",
384 },
385 {
386 .mi_type = GSM_MI_TYPE_IMSI | GSM_MI_ODD,
387 .mi_str = "423423",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100388 .mi_name = "IMSI-423423",
Neels Hofmeyr23187fa2018-12-05 23:24:50 +0100389 .expect_mi_tlv_hex = "1704413224f3",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100390 },
391 {
392 .mi_type = GSM_MI_TYPE_IMSI,
393 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100394 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100395 .expect_mi_tlv_hex = "170449322453",
396 },
397 {
398 .mi_type = GSM_MI_TYPE_IMSI,
399 .mi_str = "4234235",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100400 .mi_name = "IMSI-4234235",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100401 .expect_mi_tlv_hex = "170449322453",
402 .str_size = 4,
403 .expect_str = "423",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100404 },
405 {
406 .mi_type = GSM_MI_TYPE_IMEI,
407 .mi_str = "123456789012345",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100408 .mi_name = "IMEI-123456789012345",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100409 .expect_mi_tlv_hex = "17081a32547698103254",
410 },
411 {
412 .mi_type = GSM_MI_TYPE_IMEI,
413 .mi_str = "98765432109876",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100414 .mi_name = "IMEI-98765432109876",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100415 .expect_mi_tlv_hex = "170892785634129078f6",
416 },
417 {
418 .mi_type = GSM_MI_TYPE_IMEI,
419 .mi_str = "987654321098765",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100420 .mi_name = "IMEI-987654321098765",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100421 .expect_mi_tlv_hex = "17089a78563412907856",
422 },
423 {
424 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100425 .mi_str = "9876543210987654",
426 .mi_name = "IMEI-SV-9876543210987654",
427 .expect_mi_tlv_hex = "17099378563412907856f4",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100428 },
429 {
430 .mi_type = GSM_MI_TYPE_IMEISV,
Harald Welte13177712019-01-20 13:41:26 +0100431 .mi_str = "9876543210987654",
432 .mi_name = "IMEI-SV-9876543210987654",
433 .expect_mi_tlv_hex = "17099378563412907856f4",
434 .str_size = 17,
435 .expect_str = "9876543210987654",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100436 },
437 {
438 /* gsm48 treats TMSI as decimal string */
439 .mi_type = GSM_MI_TYPE_TMSI,
440 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100441 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100442 .expect_mi_tlv_hex = "1705f412345678",
443 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
444 },
445 {
446 .mi_type = GSM_MI_TYPE_TMSI,
447 .mi_str = "12648430", /* 0xc0ffee as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100448 .mi_name = "TMSI-0x00C0FFEE",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100449 .expect_mi_tlv_hex = "1705f400c0ffee",
450 .expect_rc = 8, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
451 },
452 {
453 .mi_type = GSM_MI_TYPE_TMSI,
454 .mi_str = "0",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100455 .mi_name = "TMSI-0x00000000",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100456 .expect_mi_tlv_hex = "1705f400000000",
457 .expect_rc = 1, /* exception: gsm48_mi_to_string() for TMSI returns strlen(), not bytes! */
458 },
459 {
460 /* gsm48 treats TMSI as decimal string */
461 .mi_type = GSM_MI_TYPE_TMSI,
462 .mi_str = "305419896", /* 0x12345678 as decimal */
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100463 .mi_name = "TMSI-0x12345678",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100464 .expect_mi_tlv_hex = "1705f412345678",
465 .str_size = 5,
466 .expect_str = "3054",
467 .expect_rc = 9, /* exception: gsm48_mi_to_string() for TMSI returns would-be strlen() like snprintf()! */
468 },
469 {
470 .mi_type = GSM_MI_TYPE_NONE,
471 .mi_str = "123",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100472 .mi_name = "unknown",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100473 .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
474 .expect_str = "",
475 },
476 {
477 .mi_type = GSM_MI_TYPE_NONE,
478 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100479 .mi_name = "unknown",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100480 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
481 .expect_str = "",
482 },
483 {
484 .mi_type = GSM_MI_ODD,
485 .mi_str = "1234",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100486 .mi_name = "unknown",
Neels Hofmeyr23187fa2018-12-05 23:24:50 +0100487 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
Neels Hofmeyr49686282018-12-05 21:32:21 +0100488 .expect_str = "",
489 },
490};
491
492static void test_mid_encode_decode(void)
493{
494 int i;
495
496 printf("\nTesting Mobile Identity conversions\n");
497
498 for (i = 0; i < ARRAY_SIZE(test_mid_encode_decode_tests); i++) {
499 const struct test_mid_encode_decode_test *t = &test_mid_encode_decode_tests[i];
500 uint8_t tlv_buf[64];
501 uint8_t *mi_buf;
502 int tlv_len;
503 int mi_len;
504 const char *tlv_hex;
505 char str[64] = {};
506 size_t str_size = t->str_size ? : sizeof(str);
507 const char *expect_str = t->expect_str ? : t->mi_str;
508 int expect_rc = t->expect_rc ? : strlen(expect_str)+1;
509 int rc;
510 int str_len;
511
512 printf("- %s %s\n", gsm48_mi_type_name(t->mi_type), t->mi_str);
513 if (t->mi_type == GSM_MI_TYPE_TMSI)
514 tlv_len = gsm48_generate_mid_from_tmsi(tlv_buf, (uint32_t)atoll(t->mi_str));
515 else
516 tlv_len = gsm48_generate_mid(tlv_buf, t->mi_str, t->mi_type);
517 tlv_hex = osmo_hexdump_nospc(tlv_buf, tlv_len);
518
519 printf(" -> MI-TLV-hex='%s'\n", tlv_hex);
520 if (t->expect_mi_tlv_hex && strcmp(tlv_hex, t->expect_mi_tlv_hex)) {
521 printf(" ERROR: expected '%s'\n", t->expect_mi_tlv_hex);
522 }
523
524 /* skip the GSM48_IE_MOBILE_ID tag and length */
525 mi_buf = tlv_buf + 2;
526 mi_len = tlv_len - 2;
527
528 rc = gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
529 printf(" -> MI-str=%s rc=%d\n", osmo_quote_str(str, -1), rc);
530 if (strcmp(str, expect_str))
531 printf(" ERROR: expected MI-str=%s\n", osmo_quote_str(expect_str, -1));
532 if (rc != expect_rc)
533 printf(" ERROR: expected rc=%d\n", expect_rc);
534
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100535 if (t->mi_name) {
536 const char *mi_name = osmo_mi_name(mi_buf, mi_len);
537 printf(" -> MI-name=%s\n", osmo_quote_str(mi_name, -1));
538 if (strcmp(mi_name, t->mi_name))
539 printf(" ERROR: expected MI-name=%s\n", osmo_quote_str(t->mi_name, -1));
540 }
541
Neels Hofmeyr49686282018-12-05 21:32:21 +0100542 /* Now make sure the resulting string is always '\0' terminated.
543 * The above started out with a zeroed buffer, now repeat with a tainted one. */
544 str_len = strlen(str);
545 str[str_len] = '!';
546 gsm48_mi_to_string(str, str_size, mi_buf, mi_len);
547 if (strlen(str) != str_len)
548 printf(" ERROR: resulting string is not explicitly nul terminated\n");
549 }
550}
551
552static const uint8_t test_mid_decode_zero_length_types[] = { GSM_MI_TYPE_IMSI, GSM_MI_TYPE_TMSI, GSM_MI_TYPE_NONE };
553
554static void test_mid_decode_zero_length(void)
555{
556 int odd;
557 uint8_t valid_mi[64];
558 int valid_mi_len;
559
560 printf("\nDecoding zero length Mobile Identities\n");
561
562 /* IMSI = 123456789012345 */
563 valid_mi_len = osmo_hexparse("1932547698103254", valid_mi, sizeof(valid_mi));
564
565 for (odd = 0; odd <= 1; odd++) {
566 int i;
567 for (i = 0; i < ARRAY_SIZE(test_mid_decode_zero_length_types); i++) {
568 uint8_t mi_type = test_mid_decode_zero_length_types[i] | (odd ? GSM_MI_ODD : 0);
569 char str[8] = {};
570 int rc;
571
572 printf("- MI type: %s%s\n", gsm48_mi_type_name(mi_type & GSM_MI_TYPE_MASK),
573 odd ? " | GSM_MI_ODD":"");
574 valid_mi[0] = (valid_mi[0] & 0xf0) | mi_type;
575
576 printf(" - writing to zero-length string:\n");
577 memset(str, '!', sizeof(str) - 1);
578 rc = gsm48_mi_to_string(str, 0, valid_mi, valid_mi_len);
579 printf(" rc=%d\n", rc);
580 if (str[0] == '!')
581 printf(" nothing written\n");
582 else
583 printf(" ERROR: Wrote to invalid memory!\n");
584
585 printf(" - writing to 1-byte-length string:\n");
586 memset(str, '!', sizeof(str) - 1);
587 rc = gsm48_mi_to_string(str, 1, valid_mi, valid_mi_len);
588 printf(" rc=%d\n", rc);
589 if (str[0] == '\0')
590 printf(" returned empty string\n");
591 else if (str[0] == '!')
592 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
593 else
594 printf(" ERROR: Wrote unexpected string %s\n", osmo_quote_str(str, 5));
595 if (str[1] != '!')
596 printf(" ERROR: Wrote to invalid memory!\n");
597
598 printf(" - decode zero-length mi:\n");
599 memset(str, '!', sizeof(str) - 1);
600 rc = gsm48_mi_to_string(str, sizeof(str), valid_mi, 0);
601 printf(" rc=%d\n", rc);
602 if (str[0] == '\0')
603 printf(" returned empty string\n");
604 else if (str[0] == '!')
605 printf(" ERROR: nothing written, expected nul-terminated empty string\n");
606 else
607 printf(" ERROR: expected empty string, got output string: %s\n", osmo_quote_str(str, -1));
608 }
609 }
610 printf("\n");
611}
612
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +0200613struct {
614 int range;
615 int arfcns_num;
616 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
617} arfcn_test_ranges[] = {
618 {OSMO_GSM48_ARFCN_RANGE_512, 12,
619 { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }},
620 {OSMO_GSM48_ARFCN_RANGE_512, 17,
621 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }},
622 {OSMO_GSM48_ARFCN_RANGE_512, 18,
623 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }},
624 {OSMO_GSM48_ARFCN_RANGE_512, 18,
625 { 1, 17, 31, 45, 58, 79, 81, 97,
626 113, 127, 213, 277, 287, 311, 331, 391,
627 417, 511 }},
628 {OSMO_GSM48_ARFCN_RANGE_512, 6,
629 { 1, 17, 31, 45, 58, 79 }},
630 {OSMO_GSM48_ARFCN_RANGE_512, 6,
631 { 10, 17, 31, 45, 58, 79 }},
632 {OSMO_GSM48_ARFCN_RANGE_1024, 17,
633 { 0, 17, 31, 45, 58, 79, 81, 97,
634 113, 127, 213, 277, 287, 311, 331, 391,
635 1023 }},
636 {OSMO_GSM48_ARFCN_RANGE_1024, 16,
637 { 17, 31, 45, 58, 79, 81, 97, 113,
638 127, 213, 277, 287, 311, 331, 391, 1023 }},
639 {-1}
640};
641
642static int test_single_range_encoding(int range, const int *orig_arfcns, int arfcns_num, int silent)
643{
644 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
645 int w[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
646 int f0_included = 0;
647 int rc, f0;
648 uint8_t chan_list[16] = {0};
649 struct gsm_sysinfo_freq dec_freq[1024] = {{0}};
650 int dec_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
651 int dec_arfcns_count = 0;
652 int arfcns_used = 0;
653 int i;
654
655 arfcns_used = arfcns_num;
656 memmove(arfcns, orig_arfcns, sizeof(arfcns));
657
658 f0 = range == OSMO_GSM48_ARFCN_RANGE_1024 ? 0 : arfcns[0];
659 /*
660 * Manipulate the ARFCN list according to the rules in J4 depending
661 * on the selected range.
662 */
663 arfcns_used = osmo_gsm48_range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included);
664
665 memset(w, 0, sizeof(w));
666 osmo_gsm48_range_enc_arfcns(range, arfcns, arfcns_used, w, 0);
667
668 if (!silent)
669 printf("range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", range, arfcns_used, f0, f0_included);
670
671 /* Select the range and the amount of bits needed */
672 switch (range) {
673 case OSMO_GSM48_ARFCN_RANGE_128:
674 osmo_gsm48_range_enc_128(chan_list, f0, w);
675 break;
676 case OSMO_GSM48_ARFCN_RANGE_256:
677 osmo_gsm48_range_enc_256(chan_list, f0, w);
678 break;
679 case OSMO_GSM48_ARFCN_RANGE_512:
680 osmo_gsm48_range_enc_512(chan_list, f0, w);
681 break;
682 case OSMO_GSM48_ARFCN_RANGE_1024:
683 osmo_gsm48_range_enc_1024(chan_list, f0, f0_included, w);
684 break;
685 default:
686 return 1;
687 };
688
689 if (!silent)
690 printf("chan_list = %s\n",
691 osmo_hexdump(chan_list, sizeof(chan_list)));
692
693 rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list),
694 0xfe, 1);
695 if (rc != 0) {
696 printf("Cannot decode freq list, rc = %d\n", rc);
697 return 1;
698 }
699
700 for (i = 0; i < ARRAY_SIZE(dec_freq); i++) {
701 if (dec_freq[i].mask &&
702 dec_arfcns_count < ARRAY_SIZE(dec_arfcns))
703 dec_arfcns[dec_arfcns_count++] = i;
704 }
705
706 if (!silent) {
707 printf("Decoded freqs %d (expected %d)\n",
708 dec_arfcns_count, arfcns_num);
709 printf("Decoded: ");
710 for (i = 0; i < dec_arfcns_count; i++) {
711 printf("%d ", dec_arfcns[i]);
712 if (dec_arfcns[i] != orig_arfcns[i])
713 printf("(!= %d) ", orig_arfcns[i]);
714 }
715 printf("\n");
716 }
717
718 if (dec_arfcns_count != arfcns_num) {
719 printf("Wrong number of arfcns\n");
720 return 1;
721 }
722
723 if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) {
724 printf("Decoding error, got wrong freqs\n");
725 printf(" w = ");
726 for (i = 0; i < ARRAY_SIZE(w); i++)
727 printf("%d ", w[i]);
728 printf("\n");
729 return 1;
730 }
731
732 return 0;
733}
734
735static void test_random_range_encoding(int range, int max_arfcn_num)
736{
737 int arfcns_num = 0;
738 int test_idx;
739 int rc, max_count;
740 int num_tests = 1024;
741
742 printf("Random range test: range %d, max num ARFCNs %d\n",
743 range, max_arfcn_num);
744
745 srandom(1);
746
747 for (max_count = 1; max_count < max_arfcn_num; max_count++) {
748 for (test_idx = 0; test_idx < num_tests; test_idx++) {
749 int count;
750 int i;
751 int min_freq = 0;
752
753 int rnd_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
754 char rnd_arfcns_set[1024] = {0};
755
756 if (range < OSMO_GSM48_ARFCN_RANGE_1024)
757 min_freq = random() % (1023 - range);
758
759 for (count = max_count; count; ) {
760 int arfcn = min_freq + random() % (range + 1);
761 OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set));
762
763 if (!rnd_arfcns_set[arfcn]) {
764 rnd_arfcns_set[arfcn] = 1;
765 count -= 1;
766 }
767 }
768
769 arfcns_num = 0;
770 for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++)
771 if (rnd_arfcns_set[i])
772 rnd_arfcns[arfcns_num++] = i;
773
774 rc = test_single_range_encoding(range, rnd_arfcns,
775 arfcns_num, 1);
776 if (rc != 0) {
777 printf("Failed on test %d, range %d, num ARFCNs %d\n",
778 test_idx, range, max_count);
779 test_single_range_encoding(range, rnd_arfcns,
780 arfcns_num, 0);
781 return;
782 }
783 }
784 }
785}
786
787static void test_range_encoding()
788{
789 int *arfcns;
790 int arfcns_num = 0;
791 int test_idx;
792 int range;
793
794 for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++)
795 {
796 arfcns_num = arfcn_test_ranges[test_idx].arfcns_num;
797 arfcns = &arfcn_test_ranges[test_idx].arfcns[0];
798 range = arfcn_test_ranges[test_idx].range;
799
800 printf("Range test %d: range %d, num ARFCNs %d\n",
801 test_idx, range, arfcns_num);
802
803 test_single_range_encoding(range, arfcns, arfcns_num, 0);
804 }
805
806 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_128, 29);
807 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_256, 22);
808 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_512, 18);
809 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_1024, 16);
810}
811
812static int freqs1[] = {
813 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980
814};
815
816static int freqs2[] = {
817 402, 460, 1, 67, 131, 197, 272, 347,
818};
819
820static int freqs3[] = {
821 68, 128, 198, 279, 353, 398, 452,
822
823};
824
825static int w_out[] = {
826 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9,
827};
828
829static int range128[] = {
830 1, 1 + 127,
831};
832
833static int range256[] = {
834 1, 1 + 128,
835};
836
837static int range512[] = {
838 1, 1+ 511,
839};
840
841
842#define VERIFY(res, cmp, wanted) \
843 if (!(res cmp wanted)) { \
844 printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
845 __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \
846 }
847
848static void test_arfcn_filter()
849{
850 int arfcns[50], i, res, f0_included;
851 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
852 arfcns[i] = (i + 1) * 2;
853
854 /* check that the arfcn is taken out. f0_included is only set for Range1024 */
855 f0_included = 24;
856 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included);
857 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
858 VERIFY(f0_included, ==, 1);
859 for (i = 0; i < res; ++i)
860 VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1));
861
862 /* check with range1024, ARFCN 0 is included */
863 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
864 arfcns[i] = i * 2;
865 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
866 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
867 VERIFY(f0_included, ==, 1);
868 for (i = 0; i < res; ++i)
869 VERIFY(arfcns[i], ==, (i + 1) * 2 - 1);
870
871 /* check with range1024, ARFCN 0 not included */
872 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
873 arfcns[i] = (i + 1) * 2;
874 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
875 VERIFY(res, ==, ARRAY_SIZE(arfcns));
876 VERIFY(f0_included, ==, 0);
877 for (i = 0; i < res; ++i)
878 VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1);
879}
880
881static void test_print_encoding()
882{
883 int rc;
884 int w[17];
885 uint8_t chan_list[16];
886 memset(chan_list, 0x23, sizeof(chan_list));
887
888 for (rc = 0; rc < ARRAY_SIZE(w); ++rc)
889 switch (rc % 3) {
890 case 0:
891 w[rc] = 0xAAAA;
892 break;
893 case 1:
894 w[rc] = 0x5555;
895 break;
896 case 2:
897 w[rc] = 0x9696;
898 break;
899 }
900
901 osmo_gsm48_range_enc_512(chan_list, (1 << 9) | 0x96, w);
902
903 printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list)));
904}
905
906static void test_si_range_helpers()
907{
908 int ws[(sizeof(freqs1)/sizeof(freqs1[0]))];
909 int i, f0 = 0xFFFFFF;
910
911 memset(&ws[0], 0x23, sizeof(ws));
912
913 i = osmo_gsm48_range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1));
914 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1);
915 VERIFY(i, ==, 2);
916
917 i = osmo_gsm48_range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2));
918 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1);
919 VERIFY(i, ==, 2);
920
921 i = osmo_gsm48_range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3));
922 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1);
923 VERIFY(i, ==, 0);
924
925 osmo_gsm48_range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0);
926
927 for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) {
928 printf("w[%d]=%d\n", i, ws[i]);
929 VERIFY(ws[i], ==, w_out[i]);
930 }
931
932 i = osmo_gsm48_range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0);
933 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_128);
934 VERIFY(f0, ==, 1);
935
936 i = osmo_gsm48_range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0);
937 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_256);
938 VERIFY(f0, ==, 1);
939
940 i = osmo_gsm48_range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0);
941 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_512);
942 VERIFY(f0, ==, 1);
943}
944
Harald Weltec8a0b932012-08-24 21:27:26 +0200945int main(int argc, char **argv)
946{
947 test_bearer_cap();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200948 test_mid_from_tmsi();
Maxd55d7d42018-02-15 11:27:18 +0100949 test_mid_from_imsi();
Neels Hofmeyr49686282018-12-05 21:32:21 +0100950 test_mid_encode_decode();
951 test_mid_decode_zero_length();
Max99377c22017-08-30 19:17:50 +0200952 test_ra_cap();
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +0100953 test_lai_encode_decode();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200954
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +0200955 test_si_range_helpers();
956 test_arfcn_filter();
957 test_print_encoding();
958 test_range_encoding();
959
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +0200960 return EXIT_SUCCESS;
Harald Weltec8a0b932012-08-24 21:27:26 +0200961}