blob: a773b3f58b62d5b992e28ff757c15b09f0041d52 [file] [log] [blame]
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001/* tests for utilities of libmsomcore */
2/*
3 * (C) 2014 Holger Hans Peter Freyther
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020023#include <osmocom/gsm/ipa.h>
Harald Welte7869baf2018-07-31 20:25:48 +020024#include <osmocom/gsm/protocol/ipaccess.h>
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020025
26#include <osmocom/core/logging.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010027#include <osmocom/core/utils.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020028#include <osmocom/core/socket.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010029
30#include <stdio.h>
Harald Welte504caac2017-10-27 17:19:59 +020031#include <ctype.h>
Harald Welte15a5f8d2018-06-06 16:58:17 +020032#include <time.h>
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +020033#include <netinet/in.h>
34#include <arpa/inet.h>
Neels Hofmeyr7079e692018-12-05 21:02:36 +010035#include <errno.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010036
37static void hexdump_test(void)
38{
39 uint8_t data[4098];
40 int i;
41
42 for (i = 0; i < ARRAY_SIZE(data); ++i)
43 data[i] = i & 0xff;
44
45 printf("Plain dump\n");
46 printf("%s\n", osmo_hexdump(data, 4));
47
48 printf("Corner case\n");
49 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
50 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
51}
52
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010053static void hexparse_test(void)
54{
55 int i;
56 int rc;
57 uint8_t data[256];
58
59 printf("\nHexparse 0..255 in lower case\n");
60 memset(data, 0, sizeof(data));
61 rc = osmo_hexparse(
62 "000102030405060708090a0b0c0d0e0f"
63 "101112131415161718191a1b1c1d1e1f"
64 "202122232425262728292a2b2c2d2e2f"
65 "303132333435363738393a3b3c3d3e3f"
66 "404142434445464748494a4b4c4d4e4f"
67 "505152535455565758595a5b5c5d5e5f"
68 "606162636465666768696a6b6c6d6e6f"
69 "707172737475767778797a7b7c7d7e7f"
70 "808182838485868788898a8b8c8d8e8f"
71 "909192939495969798999a9b9c9d9e9f"
72 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
73 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
74 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
75 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
76 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
77 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
78 , data, sizeof(data));
79 printf("rc = %d\n", rc);
80 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
81 for (i = 0; i < sizeof(data); i++)
82 OSMO_ASSERT(data[i] == i);
83
84 printf("Hexparse 0..255 in upper case\n");
85 memset(data, 0, sizeof(data));
86 rc = osmo_hexparse(
87 "000102030405060708090A0B0C0D0E0F"
88 "101112131415161718191A1B1C1D1E1F"
89 "202122232425262728292A2B2C2D2E2F"
90 "303132333435363738393A3B3C3D3E3F"
91 "404142434445464748494A4B4C4D4E4F"
92 "505152535455565758595A5B5C5D5E5F"
93 "606162636465666768696A6B6C6D6E6F"
94 "707172737475767778797A7B7C7D7E7F"
95 "808182838485868788898A8B8C8D8E8F"
96 "909192939495969798999A9B9C9D9E9F"
97 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
98 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
99 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
100 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
101 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
102 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
103 , data, sizeof(data));
104 printf("rc = %d\n", rc);
105 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
106 for (i = 0; i < sizeof(data); i++)
107 OSMO_ASSERT(data[i] == i);
108
109 printf("Hexparse 0..255 in mixed case\n");
110 memset(data, 0, sizeof(data));
111 rc = osmo_hexparse(
112 "000102030405060708090A0B0C0D0E0F"
113 "101112131415161718191A1B1C1D1E1F"
114 "202122232425262728292A2B2C2D2E2F"
115 "303132333435363738393a3b3c3d3e3f"
116 "404142434445464748494A4B4C4D4E4F"
117 "505152535455565758595a5b5c5d5e5f"
118 "606162636465666768696A6B6C6D6E6F"
119 "707172737475767778797A7B7C7D7E7F"
120 "808182838485868788898A8B8C8D8E8F"
121 "909192939495969798999A9B9C9D9E9F"
122 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
123 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
124 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
125 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
126 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
127 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
128 , data, sizeof(data));
129 printf("rc = %d\n", rc);
130 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
131 for (i = 0; i < sizeof(data); i++)
132 OSMO_ASSERT(data[i] == i);
133
Neels Hofmeyr437ed4a2017-02-14 15:54:31 +0100134 printf("Hexparse 0..255 with whitespace\n");
135 memset(data, 0, sizeof(data));
136 rc = osmo_hexparse(
137 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
138 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
139 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
140 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
141 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
142 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
143 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
144 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
145 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
146 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
147 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
148 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
149 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
150 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
151 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
152 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
153 , data, sizeof(data));
154 printf("rc = %d\n", rc);
155 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
156 for (i = 0; i < sizeof(data); i++)
157 OSMO_ASSERT(data[i] == i);
158
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100159 printf("Hexparse with buffer too short\n");
160 memset(data, 0, sizeof(data));
161 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
162 printf("rc = %d\n", rc);
163
164 printf("Hexparse with uneven amount of digits\n");
165 memset(data, 0, sizeof(data));
166 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
167 printf("rc = %d\n", rc);
168
169 printf("Hexparse with invalid char\n");
170 memset(data, 0, sizeof(data));
171 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
172 printf("rc = %d\n", rc);
173}
174
Harald Welte7869baf2018-07-31 20:25:48 +0200175static void test_ipa_ccm_id_resp_parsing(void)
176{
177 struct tlv_parsed tvp;
178 int rc;
179
180 static const uint8_t id_resp_data[] = {
181 0x00, 0x13, IPAC_IDTAG_MACADDR,
182 '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
183 0x00, 0x11, IPAC_IDTAG_IPADDR,
184 '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
185 0x00, 0x0a, IPAC_IDTAG_UNIT,
186 '1','2','3','4','/','0','/','0','\0',
187 0x00, 0x02, IPAC_IDTAG_LOCATION1,
188 '\0',
189 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
190 'B','T','S','_','N','B','T','1','3','1','G','\0',
191 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
192 '1','6','5','a','0','2','9','_','5','5','\0',
193 0x00, 0x14, IPAC_IDTAG_SWVERSION,
194 '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
195 0x00, 0x18, IPAC_IDTAG_UNITNAME,
196 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
197 0x00, 0x0a, IPAC_IDTAG_SERNR,
198 '0','0','1','1','0','7','8','1','\0'
199 };
200
201 printf("\nTesting IPA CCM ID RESP parsing\n");
202
203 rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
204 OSMO_ASSERT(rc == 0);
205
206 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
207 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
208 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
209 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
210 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
211 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
212 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
213 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
214 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
215 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
216 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
217 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
218 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
219 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
220 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
221 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
222 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
223 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
224 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
225}
226
227static void test_ipa_ccm_id_get_parsing(void)
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200228{
229 struct tlv_parsed tvp;
230 int rc;
231
Harald Welte48fd0192018-07-31 20:19:49 +0200232 /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
Harald Welte7869baf2018-07-31 20:25:48 +0200233 static const uint8_t id_get_data[] = {
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200234 0x01, 0x08,
235 0x01, 0x07,
236 0x01, 0x02,
237 0x01, 0x03,
238 0x01, 0x04,
239 0x01, 0x05,
240 0x01, 0x01,
241 0x01, 0x00,
242 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
243 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
244 };
245
Harald Welte7869baf2018-07-31 20:25:48 +0200246 printf("\nTesting IPA CCM ID GET parsing\n");
247
248 rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200249 OSMO_ASSERT(rc == 0);
250
251 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
252 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
253
254 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
255 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
256
257 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
258 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
259
260 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
261 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
262
263 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
264 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
265
266 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
267 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
268
269 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
270 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
271
272 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
273 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
274
275 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
276 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
277
278 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
279 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
280
281 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
282}
283
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200284static struct {
285 const char *str;
286 int min_digits;
287 int max_digits;
288 bool require_even;
289 bool expect_ok;
290} test_hexstrs[] = {
291 { NULL, 0, 10, false, true },
292 { NULL, 1, 10, false, false },
293 { "", 0, 10, false, true },
294 { "", 1, 10, false, false },
295 { " ", 0, 10, false, false },
296 { "1", 0, 10, false, true },
297 { "1", 1, 10, false, true },
298 { "1", 1, 10, true, false },
299 { "1", 2, 10, false, false },
300 { "123", 1, 10, false, true },
301 { "123", 1, 10, true, false },
302 { "123", 4, 10, false, false },
303 { "1234", 4, 10, true, true },
304 { "12345", 4, 10, true, false },
305 { "123456", 4, 10, true, true },
306 { "1234567", 4, 10, true, false },
307 { "12345678", 4, 10, true, true },
308 { "123456789", 4, 10, true, false },
309 { "123456789a", 4, 10, true, true },
310 { "123456789ab", 4, 10, true, false },
311 { "123456789abc", 4, 10, true, false },
312 { "123456789ab", 4, 10, false, false },
313 { "123456789abc", 4, 10, false, false },
314 { "0123456789abcdefABCDEF", 0, 100, false, true },
315 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
316 { "foobar", 0, 100, false, false },
317 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
318 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
319 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
320};
321
322bool test_is_hexstr()
323{
324 int i;
325 bool pass = true;
326 bool ok = true;
327 printf("\n----- %s\n", __func__);
328
329 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
330 ok = osmo_is_hexstr(test_hexstrs[i].str,
331 test_hexstrs[i].min_digits,
332 test_hexstrs[i].max_digits,
333 test_hexstrs[i].require_even);
334 pass = pass && (ok == test_hexstrs[i].expect_ok);
335 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
336 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
337 test_hexstrs[i].str,
338 test_hexstrs[i].min_digits,
339 test_hexstrs[i].max_digits,
340 test_hexstrs[i].require_even,
341 test_hexstrs[i].expect_ok ? "valid" : "invalid");
342 }
343 return pass;
344}
345
Harald Welte504caac2017-10-27 17:19:59 +0200346struct bcdcheck {
347 uint8_t bcd;
348 char ch;
349};
350
351static const struct bcdcheck bcdchecks[] = {
352 { 0, '0' },
353 { 1, '1' },
354 { 2, '2' },
355 { 3, '3' },
356 { 4, '4' },
357 { 5, '5' },
358 { 6, '6' },
359 { 7, '7' },
360 { 8, '8' },
361 { 9, '9' },
362 { 0xA, 'A' },
363 { 0xB, 'B' },
364 { 0xC, 'C' },
365 { 0xD, 'D' },
366 { 0xE, 'E' },
367 { 0xF, 'F' },
368};
369
370static void bcd_test(void)
371{
372 int i;
373
374 printf("\nTesting BCD conversion\n");
375 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
376 const struct bcdcheck *check = &bcdchecks[i];
377 char ch = osmo_bcd2char(check->bcd);
378 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
379 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
380 /* test char -> bcd back-coversion */
381 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
382 /* test for lowercase hex char */
383 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
384 }
385}
386
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100387struct bcd2str_test {
388 const char *bcd_hex;
389 int start_nibble;
390 int end_nibble;
391 bool allow_hex;
392 size_t str_size;
393 const char *expect_str;
394 int expect_rc;
395};
396
397static const struct bcd2str_test bcd2str_tests[] = {
398 {
399 .bcd_hex = "1a 32 54 76 98 f0",
400 .start_nibble = 1,
401 .end_nibble = 11,
402 .expect_str = "1234567890",
403 .expect_rc = 10,
404 },
405 {
406 .bcd_hex = "1a 32 a4 cb 9d f0",
407 .start_nibble = 1,
408 .end_nibble = 11,
409 .expect_str = "1234ABCD90",
410 .expect_rc = -EINVAL,
411 },
412 {
413 .bcd_hex = "1a 32 a4 cb 9d f0",
414 .start_nibble = 1,
415 .end_nibble = 11,
416 .allow_hex = true,
417 .expect_str = "1234ABCD90",
418 .expect_rc = 10,
419 },
420 {
421 .bcd_hex = "1a 32 54 76 98 f0",
422 .start_nibble = 1,
423 .end_nibble = 12,
424 .expect_str = "1234567890F",
425 .expect_rc = -EINVAL,
426 },
427 {
428 .bcd_hex = "1a 32 54 76 98 f0",
429 .start_nibble = 1,
430 .end_nibble = 12,
431 .allow_hex = true,
432 .expect_str = "1234567890F",
433 .expect_rc = 11,
434 },
435 {
436 .bcd_hex = "1a 32 54 76 98 f0",
437 .start_nibble = 0,
438 .end_nibble = 12,
439 .allow_hex = true,
440 .expect_str = "A1234567890F",
441 .expect_rc = 12,
442 },
443 {
444 .bcd_hex = "1a 32 54 76 98 f0",
445 .start_nibble = 1,
446 .end_nibble = 12,
447 .str_size = 5,
448 .expect_str = "1234",
449 .expect_rc = 11,
450 },
451 {
452 .bcd_hex = "",
453 .start_nibble = 1,
454 .end_nibble = 1,
455 .expect_str = "",
456 .expect_rc = 0,
457 },
458};
459
460static void bcd2str_test(void)
461{
462 int i;
463 uint8_t bcd[64];
464 int rc;
465
466 printf("\nTesting bcd to string conversion\n");
467
468 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
469 const struct bcd2str_test *t = &bcd2str_tests[i];
470 char str[64] = {};
471 size_t str_size = t->str_size ? : sizeof(str);
472
473 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
474
475 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
476 t->start_nibble, t->end_nibble, str_size);
477 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
478
479 printf(" rc=%d\n", rc);
480
481 OSMO_ASSERT(str[str_size-1] == '\0');
482 printf(" -> %s\n", osmo_quote_str(str, -1));
483
484 if (rc != t->expect_rc)
485 printf(" ERROR: expected rc=%d\n", t->expect_rc);
486 if (strcmp(str, t->expect_str))
487 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
488 }
489
490 printf("- zero output buffer\n");
491 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
492 printf(" bcd2str(NULL, ...) -> %d\n", rc);
493 OSMO_ASSERT(rc < 0);
494 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
495 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
496 OSMO_ASSERT(rc < 0);
497}
498
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100499static void str_escape_test(void)
500{
501 int i;
502 int j;
503 uint8_t in_buf[32];
504 char out_buf[11];
505 const char *printable = "printable";
506 const char *res;
507
508 printf("\nTesting string escaping\n");
509 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100510 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100511 for (j = 0; j < 16; j++) {
512 for (i = 0; i < 16; i++)
513 in_buf[i] = (j << 4) | i;
514 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
515 }
516
517 printf("- nul terminated:\n");
518 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
519
520 printf("- passthru:\n");
521 res = osmo_escape_str(printable, -1);
522 if (res != printable)
523 printf("NOT passed through! \"%s\"\n", res);
524 else
525 printf("passed through unchanged \"%s\"\n", res);
526
527 printf("- zero length:\n");
528 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
529
530 printf("- truncation when too long:\n");
531 memset(in_buf, 'x', sizeof(in_buf));
532 in_buf[0] = '\a';
533 in_buf[7] = 'E';
534 memset(out_buf, 0x7f, sizeof(out_buf));
535 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
536 OSMO_ASSERT(out_buf[10] == 0x7f);
537
538 printf("- passthrough without truncation when no escaping needed:\n");
539 memset(in_buf, 'x', sizeof(in_buf));
540 in_buf[19] = 'E';
541 in_buf[20] = '\0';
542 memset(out_buf, 0x7f, sizeof(out_buf));
543 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, -1, out_buf, 10));
544 OSMO_ASSERT(out_buf[0] == 0x7f);
545}
546
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200547static void str_quote_test(void)
548{
549 int i;
550 int j;
551 uint8_t in_buf[32];
552 char out_buf[11];
553 const char *printable = "printable";
554 const char *res;
555
556 printf("\nTesting string quoting\n");
557 printf("- all chars from 0 to 255 in batches of 16:\n");
558 in_buf[16] = '\0';
559 for (j = 0; j < 16; j++) {
560 for (i = 0; i < 16; i++)
561 in_buf[i] = (j << 4) | i;
562 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
563 }
564
565 printf("- nul terminated:\n");
566 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
567
568 printf("- never passthru:\n");
569 res = osmo_quote_str(printable, -1);
570 if (res != printable)
571 printf("NOT passed through. '%s'\n", res);
572 else
573 printf("passed through unchanged '%s'\n", res);
574
575 printf("- zero length:\n");
576 printf("'%s'\n", osmo_quote_str("omitted", 0));
577
578 printf("- truncation when too long:\n");
579 memset(in_buf, 'x', sizeof(in_buf));
580 in_buf[0] = '\a';
581 in_buf[5] = 'E';
582 memset(out_buf, 0x7f, sizeof(out_buf));
583 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
584 OSMO_ASSERT(out_buf[10] == 0x7f);
585
586 printf("- always truncation, even when no escaping needed:\n");
587 memset(in_buf, 'x', sizeof(in_buf));
588 in_buf[6] = 'E'; /* dst has 10, less 2 quotes and nul, leaves 7, i.e. in[6] is last */
589 in_buf[20] = '\0';
590 memset(out_buf, 0x7f, sizeof(out_buf));
591 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
592 OSMO_ASSERT(out_buf[0] == '"');
593
594 printf("- try to feed too little buf for quoting:\n");
595 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
596
597 printf("- NULL string becomes a \"NULL\" literal:\n");
598 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
599}
600
Harald Welte15a5f8d2018-06-06 16:58:17 +0200601static void isqrt_test(void)
602{
603 int i;
604
605 printf("\nTesting integer square-root\n");
606 srand(time(NULL));
607 for (i = 0; i < 1024; i++) {
608 uint16_t x;
609 uint32_t r = rand();
610 if (RAND_MAX < UINT16_MAX)
611 x = r * (UINT16_MAX/RAND_MAX);
612 else
613 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200614 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200615 uint32_t y = osmo_isqrt32(sq);
616 if (y != x)
617 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
618 }
619}
620
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200621
622struct osmo_sockaddr_to_str_and_uint_test_case {
623 uint16_t port;
624 bool omit_port;
625 const char *addr;
626 unsigned int addr_len;
627 bool omit_addr;
628 unsigned int expect_rc;
629 const char *expect_returned_addr;
630};
631
632struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
633 {
634 .port = 0,
635 .addr = "0.0.0.0",
636 .addr_len = 20,
637 .expect_rc = 7,
638 },
639 {
640 .port = 65535,
641 .addr = "255.255.255.255",
642 .addr_len = 20,
643 .expect_rc = 15,
644 },
645 {
646 .port = 1234,
647 .addr = "234.23.42.123",
648 .addr_len = 20,
649 .expect_rc = 13,
650 },
651 {
652 .port = 1234,
653 .addr = "234.23.42.123",
654 .addr_len = 10,
655 .expect_rc = 13,
656 .expect_returned_addr = "234.23.42",
657 },
658 {
659 .port = 1234,
660 .omit_port = true,
661 .addr = "234.23.42.123",
662 .addr_len = 20,
663 .expect_rc = 13,
664 },
665 {
666 .port = 1234,
667 .addr = "234.23.42.123",
668 .omit_addr = true,
669 .expect_rc = 0,
670 .expect_returned_addr = "",
671 },
672 {
673 .port = 1234,
674 .addr = "234.23.42.123",
675 .addr_len = 0,
676 .expect_rc = 13,
677 .expect_returned_addr = "",
678 },
679 {
680 .port = 1234,
681 .addr = "234.23.42.123",
682 .omit_port = true,
683 .omit_addr = true,
684 .expect_rc = 0,
685 .expect_returned_addr = "",
686 },
687};
688
689static void osmo_sockaddr_to_str_and_uint_test(void)
690{
691 int i;
692 printf("\n%s\n", __func__);
693
694 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
695 struct osmo_sockaddr_to_str_and_uint_test_case *t =
696 &osmo_sockaddr_to_str_and_uint_test_data[i];
697
698 struct sockaddr_in sin = {
699 .sin_family = AF_INET,
700 .sin_port = htons(t->port),
701 };
702 inet_aton(t->addr, &sin.sin_addr);
703
704 char addr[20] = {};
705 uint16_t port = 0;
706 unsigned int rc;
707
708 rc = osmo_sockaddr_to_str_and_uint(
709 t->omit_addr? NULL : addr, t->addr_len,
710 t->omit_port? NULL : &port,
711 (const struct sockaddr*)&sin);
712
713 printf("[%d] %s:%u%s%s addr_len=%u --> %s:%u rc=%u\n",
714 i,
715 t->addr ? : "-",
716 t->port,
717 t->omit_addr ? " (omit addr)" : "",
718 t->omit_port ? " (omit port)" : "",
719 t->addr_len,
720 addr, port, rc);
721 if (rc != t->expect_rc)
722 printf("ERROR: Expected rc = %u\n", t->expect_rc);
723 if (!t->expect_returned_addr)
724 t->expect_returned_addr = t->addr;
725 if (strcmp(t->expect_returned_addr, addr))
726 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
727 if (!t->omit_port && port != t->port)
728 printf("ERROR: Expected port = %u\n", t->port);
729 }
730}
731
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200732struct osmo_str_tolowupper_test_data {
733 const char *in;
734 bool use_static_buf;
735 size_t buflen;
736 const char *expect_lower;
737 const char *expect_upper;
738 size_t expect_rc;
739 size_t expect_rc_inplace;
740};
741
742struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
743 {
744 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
745 .use_static_buf = true,
746 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
747 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
748 },
749 {
750 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
751 .buflen = 99,
752 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
753 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
754 .expect_rc = 62,
755 .expect_rc_inplace = 62,
756 },
757 {
758 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
759 .buflen = 0,
760 .expect_lower = "Unset",
761 .expect_upper = "Unset",
762 .expect_rc = 62,
763 .expect_rc_inplace = 0,
764 },
765 {
766 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
767 .buflen = 1,
768 .expect_lower = "",
769 .expect_upper = "",
770 .expect_rc = 62,
771 .expect_rc_inplace = 0,
772 },
773 {
774 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
775 .buflen = 2,
776 .expect_lower = "a",
777 .expect_upper = "A",
778 .expect_rc = 62,
779 .expect_rc_inplace = 1,
780 },
781 {
782 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
783 .buflen = 28,
784 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
785 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
786 .expect_rc = 62,
787 .expect_rc_inplace = 27,
788 },
789};
790
791
792static void osmo_str_tolowupper_test()
793{
794 int i;
795 char buf[128];
796 bool ok = true;
797 printf("\n%s\n", __func__);
798
799 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
800 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
801 size_t rc = 0;
802 const char *res;
803
804 /* tolower */
805 if (d->use_static_buf) {
806 res = osmo_str_tolower(d->in);
807 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
808 printf(" = %s\n", osmo_quote_str(res, -1));
809 } else {
810 OSMO_ASSERT(sizeof(buf) >= d->buflen);
811 osmo_strlcpy(buf, "Unset", sizeof(buf));
812 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
813 res = buf;
814 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
815 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
816 }
817
818 if (strcmp(res, d->expect_lower)) {
819 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
820 " got %s\n", i, osmo_quote_str(res, -1));
821 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
822 ok = false;
823 }
824
825 if (!d->use_static_buf && d->expect_rc != rc) {
826 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
827 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
828 ok = false;
829 }
830
831 /* tolower, in-place */
832 if (!d->use_static_buf) {
833 osmo_strlcpy(buf,
834 d->buflen ? d->in : "Unset",
835 sizeof(buf));
836 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
837 res = buf;
838 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
839 d->buflen, osmo_quote_str(d->in, -1));
840 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
841
842 if (strcmp(res, d->expect_lower)) {
843 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
844 " got %s\n", i, osmo_quote_str(res, -1));
845 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
846 ok = false;
847 }
848
849 if (d->expect_rc_inplace != rc) {
850 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
851 " got rc=%zu, expected rc=%zu\n",
852 i, rc, d->expect_rc_inplace);
853 ok = false;
854 }
855 }
856
857 /* toupper */
858 if (d->use_static_buf) {
859 res = osmo_str_toupper(d->in);
860 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
861 printf(" = %s\n", osmo_quote_str(res, -1));
862 } else {
863 OSMO_ASSERT(sizeof(buf) >= d->buflen);
864 osmo_strlcpy(buf, "Unset", sizeof(buf));
865 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
866 res = buf;
867 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
868 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
869 }
870
871 if (strcmp(res, d->expect_upper)) {
872 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
873 " got %s\n", i, osmo_quote_str(res, -1));
874 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
875 ok = false;
876 }
877
878 if (!d->use_static_buf && d->expect_rc != rc) {
879 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
880 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
881 ok = false;
882 }
883
884 /* toupper, in-place */
885 if (!d->use_static_buf) {
886 osmo_strlcpy(buf,
887 d->buflen ? d->in : "Unset",
888 sizeof(buf));
889 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
890 res = buf;
891 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
892 d->buflen, osmo_quote_str(d->in, -1));
893 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
894
895 if (strcmp(res, d->expect_upper)) {
896 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
897 " got %s\n", i, osmo_quote_str(res, -1));
898 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
899 ok = false;
900 }
901
902 if (d->expect_rc_inplace != rc) {
903 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
904 " got rc=%zu, expected rc=%zu\n",
905 i, rc, d->expect_rc_inplace);
906 ok = false;
907 }
908 }
909 }
910
911 OSMO_ASSERT(ok);
912}
913
914
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100915int main(int argc, char **argv)
916{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200917 static const struct log_info log_info = {};
918 log_init(&log_info, NULL);
919
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100920 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100921 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +0200922 test_ipa_ccm_id_get_parsing();
923 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200924 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +0200925 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100926 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100927 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200928 str_quote_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +0200929 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200930 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200931 osmo_str_tolowupper_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100932 return 0;
933}