blob: 96178237c0355056cb2541bf1d208f30578c5c4e [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",
Neels Hofmeyr02fd83d2019-01-05 00:38:54 +0100389 .mi_name = "IMSI-423423",
Neels Hofmeyr23187fa2018-12-05 23:24:50 +0100390 .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",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100474 .expect_mi_tlv_hex = "17021832", /* encoding invalid MI type */
475 .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",
Neels Hofmeyr49686282018-12-05 21:32:21 +0100481 .expect_mi_tlv_hex = "17031032f4", /* encoding invalid MI type */
482 .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",
Neels Hofmeyr23187fa2018-12-05 23:24:50 +0100488 .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
525 /* skip the GSM48_IE_MOBILE_ID tag and length */
526 mi_buf = tlv_buf + 2;
527 mi_len = tlv_len - 2;
528
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
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700614static const struct bcd_number_test {
615 /* Human-readable test name */
616 const char *test_name;
617
618 /* To be encoded number in ASCII */
619 const char *enc_ascii;
620 /* Expected encoding result in HEX */
621 const char *enc_hex;
622 /* Optional header length (LHV) */
623 uint8_t enc_h_len;
624 /* Expected return code */
625 int enc_rc;
626
627 /* To be decoded buffer in HEX */
628 const char *dec_hex;
629 /* Expected decoding result in ASCII */
630 const char *dec_ascii;
631 /* Optional header length (LHV) */
632 uint8_t dec_h_len;
633 /* Expected return code */
634 int dec_rc;
635
636 /* Encoding buffer limit (0 means unlimited) */
637 size_t enc_buf_lim;
638 /* Decoding buffer limit (0 means unlimited) */
639 size_t dec_buf_lim;
640} bcd_number_test_set[] = {
641 {
642 .test_name = "regular 9-digit MSISDN",
643
644 /* Encoding test */
645 .enc_ascii = "123456789",
646 .enc_hex = "0521436587f9",
647 .enc_rc = 6,
648
649 /* Decoding test */
650 .dec_hex = "0521436587f9",
651 .dec_ascii = "123456789",
652 },
653 {
654 .test_name = "regular 6-digit MSISDN with optional header (LHV)",
655
656 /* Encoding test */
657 .enc_ascii = "123456",
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +0700658 .enc_hex = "07ffffffff214365",
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700659 .enc_h_len = 4, /* LHV */
660 .enc_rc = 4 + 4,
661
662 /* Decoding test */
663 .dec_hex = "07deadbeef214365",
664 .dec_ascii = "123456",
665 .dec_h_len = 4, /* LHV */
666 },
667 {
668 .test_name = "long 15-digit (maximum) MSISDN",
669
670 /* Encoding test */
671 .enc_ascii = "123456789012345",
672 .enc_hex = "0821436587092143f5",
673 .enc_rc = 9,
674
675 /* Decoding test */
676 .dec_hex = "0821436587092143f5",
677 .dec_ascii = "123456789012345",
678 },
679 {
680 .test_name = "long 15-digit (maximum) MSISDN, limited buffer",
681
682 /* Encoding test */
683 .enc_ascii = "123456789012345",
684 .enc_hex = "0821436587092143f5",
685 .enc_rc = 9,
686
687 /* Decoding test */
688 .dec_hex = "0821436587092143f5",
689 .dec_ascii = "123456789012345",
690
691 /* Buffer length limitations */
692 .dec_buf_lim = 15 + 1,
693 .enc_buf_lim = 9,
694 },
695 {
696 .test_name = "to be truncated 20-digit MSISDN",
697
698 /* Encoding test (not enough room in buffer) */
699 .enc_ascii = "12345678901234567890",
700 .enc_hex = "", /* nothing */
701 .enc_rc = -EIO,
702
703 /* Decoding test (one 5 digits do not fit) */
704 .dec_hex = "0a21436587092143658709",
705 .dec_ascii = "123456789012345",
Vadim Yanitskiy71940872019-05-26 00:49:57 +0700706 .dec_rc = -ENOSPC,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700707
708 /* Buffer length limitations */
709 .dec_buf_lim = 15 + 1, /* 5 digits less */
710 .enc_buf_lim = 9,
711 },
712 {
713 .test_name = "LV incorrect length",
714 .dec_hex = "05214365", /* should be 0x03 */
715 .dec_ascii = "(none)",
Vadim Yanitskiye4799f52019-05-26 00:55:20 +0700716 .dec_rc = -EINVAL,
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700717 },
718 {
719 .test_name = "empty input buffer",
720
721 /* Encoding test */
722 .enc_ascii = "",
723 .enc_hex = "00",
724 .enc_rc = 1,
725
726 /* Decoding test */
727 .dec_hex = "",
728 .dec_ascii = "(none)",
729 .dec_rc = -EIO,
730 },
Oliver Smith186f8782019-06-06 16:11:32 +0200731 {
732 .test_name = "decoding buffer is one byte too small (OS#4049)",
733
734 /* Decoding test */
735 .dec_hex = "022143", /* "1234" */
736 .dec_ascii = "123", /* '4' was truncated */
737 .dec_rc = -ENOSPC,
738
739 /* Buffer length limitations */
740 .dec_buf_lim = 4,
741 },
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700742};
743
744static void test_bcd_number_encode_decode()
745{
746 const struct bcd_number_test *test;
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +0700747 uint8_t buf_enc[0xff] = { 0xff };
748 char buf_dec[0xff] = { 0xff };
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700749 size_t buf_len, i;
750 int rc;
751
752 printf("BSD number encoding / decoding test\n");
753
754 for (i = 0; i < ARRAY_SIZE(bcd_number_test_set); i++) {
755 test = &bcd_number_test_set[i];
756 printf("- Running test: %s\n", test->test_name);
757
758 if (test->enc_ascii) {
759 if (test->enc_buf_lim)
760 buf_len = test->enc_buf_lim;
761 else
762 buf_len = sizeof(buf_enc);
763
764 printf(" - Encoding ASCII (buffer limit=%zu) '%s'...\n",
765 test->enc_buf_lim, test->enc_ascii);
766
767 rc = gsm48_encode_bcd_number(buf_enc, buf_len,
768 test->enc_h_len, test->enc_ascii);
769 printf(" - Expected: (rc=%d) '%s'\n",
770 test->enc_rc, test->enc_hex);
771 printf(" - Actual: (rc=%d) '%s'\n",
772 rc, osmo_hexdump_nospc(buf_enc, rc >= 0 ? rc : 0));
773 }
774
775 if (test->dec_hex) {
776 /* Parse a HEX string */
777 rc = osmo_hexparse(test->dec_hex, buf_enc, sizeof(buf_enc));
778 OSMO_ASSERT(rc >= 0);
779
780 if (test->dec_buf_lim)
781 buf_len = test->dec_buf_lim;
782 else
783 buf_len = sizeof(buf_dec);
784
785 printf(" - Decoding HEX (buffer limit=%zu) '%s'...\n",
786 test->dec_buf_lim, test->dec_hex);
787
788 rc = gsm48_decode_bcd_number2(buf_dec, buf_len,
789 buf_enc, rc, test->dec_h_len);
790 printf(" - Expected: (rc=%d) '%s'\n",
791 test->dec_rc, test->dec_ascii);
792 printf(" - Actual: (rc=%d) '%s'\n",
Vadim Yanitskiy71940872019-05-26 00:49:57 +0700793 rc, (rc == 0 || rc == -ENOSPC) ? buf_dec : "(none)");
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700794 }
Vadim Yanitskiy1dc82642019-05-27 00:53:54 +0700795
796 /* Poison buffers between the test iterations */
797 memset(buf_enc, 0xff, sizeof(buf_enc));
798 memset(buf_dec, 0xff, sizeof(buf_dec));
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +0700799 }
800
801 printf("\n");
802}
803
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +0200804struct {
805 int range;
806 int arfcns_num;
807 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
808} arfcn_test_ranges[] = {
809 {OSMO_GSM48_ARFCN_RANGE_512, 12,
810 { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }},
811 {OSMO_GSM48_ARFCN_RANGE_512, 17,
812 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }},
813 {OSMO_GSM48_ARFCN_RANGE_512, 18,
814 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }},
815 {OSMO_GSM48_ARFCN_RANGE_512, 18,
816 { 1, 17, 31, 45, 58, 79, 81, 97,
817 113, 127, 213, 277, 287, 311, 331, 391,
818 417, 511 }},
819 {OSMO_GSM48_ARFCN_RANGE_512, 6,
820 { 1, 17, 31, 45, 58, 79 }},
821 {OSMO_GSM48_ARFCN_RANGE_512, 6,
822 { 10, 17, 31, 45, 58, 79 }},
823 {OSMO_GSM48_ARFCN_RANGE_1024, 17,
824 { 0, 17, 31, 45, 58, 79, 81, 97,
825 113, 127, 213, 277, 287, 311, 331, 391,
826 1023 }},
827 {OSMO_GSM48_ARFCN_RANGE_1024, 16,
828 { 17, 31, 45, 58, 79, 81, 97, 113,
829 127, 213, 277, 287, 311, 331, 391, 1023 }},
830 {-1}
831};
832
833static int test_single_range_encoding(int range, const int *orig_arfcns, int arfcns_num, int silent)
834{
835 int arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
836 int w[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS];
837 int f0_included = 0;
838 int rc, f0;
839 uint8_t chan_list[16] = {0};
840 struct gsm_sysinfo_freq dec_freq[1024] = {{0}};
841 int dec_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
842 int dec_arfcns_count = 0;
843 int arfcns_used = 0;
844 int i;
845
846 arfcns_used = arfcns_num;
847 memmove(arfcns, orig_arfcns, sizeof(arfcns));
848
849 f0 = range == OSMO_GSM48_ARFCN_RANGE_1024 ? 0 : arfcns[0];
850 /*
851 * Manipulate the ARFCN list according to the rules in J4 depending
852 * on the selected range.
853 */
854 arfcns_used = osmo_gsm48_range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included);
855
856 memset(w, 0, sizeof(w));
857 osmo_gsm48_range_enc_arfcns(range, arfcns, arfcns_used, w, 0);
858
859 if (!silent)
860 printf("range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", range, arfcns_used, f0, f0_included);
861
862 /* Select the range and the amount of bits needed */
863 switch (range) {
864 case OSMO_GSM48_ARFCN_RANGE_128:
865 osmo_gsm48_range_enc_128(chan_list, f0, w);
866 break;
867 case OSMO_GSM48_ARFCN_RANGE_256:
868 osmo_gsm48_range_enc_256(chan_list, f0, w);
869 break;
870 case OSMO_GSM48_ARFCN_RANGE_512:
871 osmo_gsm48_range_enc_512(chan_list, f0, w);
872 break;
873 case OSMO_GSM48_ARFCN_RANGE_1024:
874 osmo_gsm48_range_enc_1024(chan_list, f0, f0_included, w);
875 break;
876 default:
877 return 1;
878 };
879
880 if (!silent)
881 printf("chan_list = %s\n",
882 osmo_hexdump(chan_list, sizeof(chan_list)));
883
884 rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list),
885 0xfe, 1);
886 if (rc != 0) {
887 printf("Cannot decode freq list, rc = %d\n", rc);
888 return 1;
889 }
890
891 for (i = 0; i < ARRAY_SIZE(dec_freq); i++) {
892 if (dec_freq[i].mask &&
893 dec_arfcns_count < ARRAY_SIZE(dec_arfcns))
894 dec_arfcns[dec_arfcns_count++] = i;
895 }
896
897 if (!silent) {
898 printf("Decoded freqs %d (expected %d)\n",
899 dec_arfcns_count, arfcns_num);
900 printf("Decoded: ");
901 for (i = 0; i < dec_arfcns_count; i++) {
902 printf("%d ", dec_arfcns[i]);
903 if (dec_arfcns[i] != orig_arfcns[i])
904 printf("(!= %d) ", orig_arfcns[i]);
905 }
906 printf("\n");
907 }
908
909 if (dec_arfcns_count != arfcns_num) {
910 printf("Wrong number of arfcns\n");
911 return 1;
912 }
913
914 if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) {
915 printf("Decoding error, got wrong freqs\n");
916 printf(" w = ");
917 for (i = 0; i < ARRAY_SIZE(w); i++)
918 printf("%d ", w[i]);
919 printf("\n");
920 return 1;
921 }
922
923 return 0;
924}
925
926static void test_random_range_encoding(int range, int max_arfcn_num)
927{
928 int arfcns_num = 0;
929 int test_idx;
930 int rc, max_count;
931 int num_tests = 1024;
932
933 printf("Random range test: range %d, max num ARFCNs %d\n",
934 range, max_arfcn_num);
935
936 srandom(1);
937
938 for (max_count = 1; max_count < max_arfcn_num; max_count++) {
939 for (test_idx = 0; test_idx < num_tests; test_idx++) {
940 int count;
941 int i;
942 int min_freq = 0;
943
944 int rnd_arfcns[OSMO_GSM48_RANGE_ENC_MAX_ARFCNS] = {0};
945 char rnd_arfcns_set[1024] = {0};
946
947 if (range < OSMO_GSM48_ARFCN_RANGE_1024)
948 min_freq = random() % (1023 - range);
949
950 for (count = max_count; count; ) {
951 int arfcn = min_freq + random() % (range + 1);
952 OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set));
953
954 if (!rnd_arfcns_set[arfcn]) {
955 rnd_arfcns_set[arfcn] = 1;
956 count -= 1;
957 }
958 }
959
960 arfcns_num = 0;
961 for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++)
962 if (rnd_arfcns_set[i])
963 rnd_arfcns[arfcns_num++] = i;
964
965 rc = test_single_range_encoding(range, rnd_arfcns,
966 arfcns_num, 1);
967 if (rc != 0) {
968 printf("Failed on test %d, range %d, num ARFCNs %d\n",
969 test_idx, range, max_count);
970 test_single_range_encoding(range, rnd_arfcns,
971 arfcns_num, 0);
972 return;
973 }
974 }
975 }
976}
977
978static void test_range_encoding()
979{
980 int *arfcns;
981 int arfcns_num = 0;
982 int test_idx;
983 int range;
984
985 for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++)
986 {
987 arfcns_num = arfcn_test_ranges[test_idx].arfcns_num;
988 arfcns = &arfcn_test_ranges[test_idx].arfcns[0];
989 range = arfcn_test_ranges[test_idx].range;
990
991 printf("Range test %d: range %d, num ARFCNs %d\n",
992 test_idx, range, arfcns_num);
993
994 test_single_range_encoding(range, arfcns, arfcns_num, 0);
995 }
996
997 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_128, 29);
998 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_256, 22);
999 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_512, 18);
1000 test_random_range_encoding(OSMO_GSM48_ARFCN_RANGE_1024, 16);
1001}
1002
1003static int freqs1[] = {
1004 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980
1005};
1006
1007static int freqs2[] = {
1008 402, 460, 1, 67, 131, 197, 272, 347,
1009};
1010
1011static int freqs3[] = {
1012 68, 128, 198, 279, 353, 398, 452,
1013
1014};
1015
1016static int w_out[] = {
1017 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9,
1018};
1019
1020static int range128[] = {
1021 1, 1 + 127,
1022};
1023
1024static int range256[] = {
1025 1, 1 + 128,
1026};
1027
1028static int range512[] = {
1029 1, 1+ 511,
1030};
1031
1032
1033#define VERIFY(res, cmp, wanted) \
1034 if (!(res cmp wanted)) { \
1035 printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
1036 __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \
1037 }
1038
1039static void test_arfcn_filter()
1040{
1041 int arfcns[50], i, res, f0_included;
1042 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1043 arfcns[i] = (i + 1) * 2;
1044
1045 /* check that the arfcn is taken out. f0_included is only set for Range1024 */
1046 f0_included = 24;
1047 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), arfcns[0], &f0_included);
1048 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1049 VERIFY(f0_included, ==, 1);
1050 for (i = 0; i < res; ++i)
1051 VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1));
1052
1053 /* check with range1024, ARFCN 0 is included */
1054 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1055 arfcns[i] = i * 2;
1056 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1057 VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1);
1058 VERIFY(f0_included, ==, 1);
1059 for (i = 0; i < res; ++i)
1060 VERIFY(arfcns[i], ==, (i + 1) * 2 - 1);
1061
1062 /* check with range1024, ARFCN 0 not included */
1063 for (i = 0; i < ARRAY_SIZE(arfcns); ++i)
1064 arfcns[i] = (i + 1) * 2;
1065 res = osmo_gsm48_range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), 0, &f0_included);
1066 VERIFY(res, ==, ARRAY_SIZE(arfcns));
1067 VERIFY(f0_included, ==, 0);
1068 for (i = 0; i < res; ++i)
1069 VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1);
1070}
1071
1072static void test_print_encoding()
1073{
1074 int rc;
1075 int w[17];
1076 uint8_t chan_list[16];
1077 memset(chan_list, 0x23, sizeof(chan_list));
1078
1079 for (rc = 0; rc < ARRAY_SIZE(w); ++rc)
1080 switch (rc % 3) {
1081 case 0:
1082 w[rc] = 0xAAAA;
1083 break;
1084 case 1:
1085 w[rc] = 0x5555;
1086 break;
1087 case 2:
1088 w[rc] = 0x9696;
1089 break;
1090 }
1091
1092 osmo_gsm48_range_enc_512(chan_list, (1 << 9) | 0x96, w);
1093
1094 printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list)));
1095}
1096
1097static void test_si_range_helpers()
1098{
1099 int ws[(sizeof(freqs1)/sizeof(freqs1[0]))];
1100 int i, f0 = 0xFFFFFF;
1101
1102 memset(&ws[0], 0x23, sizeof(ws));
1103
1104 i = osmo_gsm48_range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1));
1105 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1);
1106 VERIFY(i, ==, 2);
1107
1108 i = osmo_gsm48_range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2));
1109 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1);
1110 VERIFY(i, ==, 2);
1111
1112 i = osmo_gsm48_range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3));
1113 printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1);
1114 VERIFY(i, ==, 0);
1115
1116 osmo_gsm48_range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0);
1117
1118 for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) {
1119 printf("w[%d]=%d\n", i, ws[i]);
1120 VERIFY(ws[i], ==, w_out[i]);
1121 }
1122
1123 i = osmo_gsm48_range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0);
1124 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_128);
1125 VERIFY(f0, ==, 1);
1126
1127 i = osmo_gsm48_range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0);
1128 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_256);
1129 VERIFY(f0, ==, 1);
1130
1131 i = osmo_gsm48_range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0);
1132 VERIFY(i, ==, OSMO_GSM48_ARFCN_RANGE_512);
1133 VERIFY(f0, ==, 1);
1134}
1135
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001136static void test_power_ctrl()
1137{
1138 int8_t rc8;
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001139 int rc;
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001140
1141 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_850, 0x00);
1142 VERIFY(rc8, ==, 1);
1143 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x02);
1144 VERIFY(rc8, ==, 3);
1145 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1800, 0x02);
1146 VERIFY(rc8, ==, 3);
1147 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x02);
1148 VERIFY(rc8, ==, 3);
1149 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_1900, 0x04);
1150 VERIFY(rc8, <, 0);
1151 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x04);
1152 VERIFY(rc8, ==, 5);
1153 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0x05);
1154 VERIFY(rc8, <, 0);
1155 rc8 = osmo_gsm48_rfpowercap2powerclass(GSM_BAND_900, 0xf2);
1156 VERIFY(rc8, <, 0);
Pau Espin Pedrole40b9632019-10-31 15:38:30 +01001157
1158 rc = ms_class_gmsk_dbm(GSM_BAND_850, 0);
1159 VERIFY(rc, <, 0);
1160 rc = ms_class_gmsk_dbm(GSM_BAND_850, 1);
1161 VERIFY(rc, ==, 43);
1162 rc = ms_class_gmsk_dbm(GSM_BAND_900, 3);
1163 VERIFY(rc, ==, 37);
1164 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 2);
1165 VERIFY(rc, ==, 24);
1166 rc = ms_class_gmsk_dbm(GSM_BAND_1800, 3);
1167 VERIFY(rc, ==, 36);
1168 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 3);
1169 VERIFY(rc, ==, 33);
1170 rc = ms_class_gmsk_dbm(GSM_BAND_1900, 4);
1171 VERIFY(rc, <, 0);
1172 rc = ms_class_gmsk_dbm(GSM_BAND_900, 5);
1173 VERIFY(rc, ==, 29);
1174 rc = ms_class_gmsk_dbm(GSM_BAND_900, 6);
1175 VERIFY(rc, <, 0);
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001176}
1177
Harald Weltec8a0b932012-08-24 21:27:26 +02001178int main(int argc, char **argv)
1179{
1180 test_bearer_cap();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001181 test_mid_from_tmsi();
Maxd55d7d42018-02-15 11:27:18 +01001182 test_mid_from_imsi();
Neels Hofmeyr49686282018-12-05 21:32:21 +01001183 test_mid_encode_decode();
1184 test_mid_decode_zero_length();
Vadim Yanitskiyaa0683d2019-05-25 23:14:00 +07001185 test_bcd_number_encode_decode();
Max99377c22017-08-30 19:17:50 +02001186 test_ra_cap();
Neels Hofmeyrd5a577b2018-02-20 21:48:07 +01001187 test_lai_encode_decode();
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001188
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001189 test_si_range_helpers();
1190 test_arfcn_filter();
1191 test_print_encoding();
1192 test_range_encoding();
Pau Espin Pedrolb99f4ca2019-10-31 13:35:22 +01001193 test_power_ctrl();
Stefan Sperlingfdf8b7b2018-07-27 12:19:15 +02001194
Holger Hans Peter Freythercd252e32013-07-03 09:56:53 +02001195 return EXIT_SUCCESS;
Harald Weltec8a0b932012-08-24 21:27:26 +02001196}