blob: 822861fb05cb0198a7e2891687016dd0af026dd7 [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];
Neels Hofmeyr0423b612019-01-14 23:32:53 +010040 char buf[256];
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010041 int i;
42
43 for (i = 0; i < ARRAY_SIZE(data); ++i)
44 data[i] = i & 0xff;
45
46 printf("Plain dump\n");
47 printf("%s\n", osmo_hexdump(data, 4));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010048 printf("%s\n", osmo_hexdump_nospc(data, 4));
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010049
50 printf("Corner case\n");
51 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
52 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
Neels Hofmeyr0423b612019-01-14 23:32:53 +010053
54#define _HEXDUMP_BUF_TEST(SIZE, DELIM, DELIM_AFTER) \
55 buf[0] = '!'; \
56 buf[1] = '\0'; \
57 printf("osmo_hexdump_buf(buf, " #SIZE ", data, 4, %s, " #DELIM_AFTER ")\n = \"%s\"\n", \
58 DELIM ? #DELIM : "NULL", \
59 osmo_hexdump_buf(buf, SIZE, data, 4, DELIM, DELIM_AFTER))
60#define HEXDUMP_BUF_TEST(DELIM) \
61 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, false); \
62 _HEXDUMP_BUF_TEST(sizeof(buf), DELIM, true); \
63 _HEXDUMP_BUF_TEST(6, DELIM, false); \
64 _HEXDUMP_BUF_TEST(7, DELIM, false); \
65 _HEXDUMP_BUF_TEST(8, DELIM, false); \
66 _HEXDUMP_BUF_TEST(6, DELIM, true); \
67 _HEXDUMP_BUF_TEST(7, DELIM, true); \
68 _HEXDUMP_BUF_TEST(8, DELIM, true)
69
70 HEXDUMP_BUF_TEST("[delim]");
71 HEXDUMP_BUF_TEST(" ");
72 HEXDUMP_BUF_TEST(":");
73 HEXDUMP_BUF_TEST("::");
74 HEXDUMP_BUF_TEST("");
75 HEXDUMP_BUF_TEST(NULL);
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010076}
77
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010078static void hexparse_test(void)
79{
80 int i;
81 int rc;
82 uint8_t data[256];
83
84 printf("\nHexparse 0..255 in lower 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 upper 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
134 printf("Hexparse 0..255 in mixed case\n");
135 memset(data, 0, sizeof(data));
136 rc = osmo_hexparse(
137 "000102030405060708090A0B0C0D0E0F"
138 "101112131415161718191A1B1C1D1E1F"
139 "202122232425262728292A2B2C2D2E2F"
140 "303132333435363738393a3b3c3d3e3f"
141 "404142434445464748494A4B4C4D4E4F"
142 "505152535455565758595a5b5c5d5e5f"
143 "606162636465666768696A6B6C6D6E6F"
144 "707172737475767778797A7B7C7D7E7F"
145 "808182838485868788898A8B8C8D8E8F"
146 "909192939495969798999A9B9C9D9E9F"
147 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
148 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
149 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
150 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
151 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
152 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
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 Hofmeyr437ed4a2017-02-14 15:54:31 +0100159 printf("Hexparse 0..255 with whitespace\n");
160 memset(data, 0, sizeof(data));
161 rc = osmo_hexparse(
162 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
163 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
164 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
165 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
166 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
167 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
168 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
169 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
170 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
171 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
172 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
173 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
174 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
175 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
176 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
177 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
178 , data, sizeof(data));
179 printf("rc = %d\n", rc);
180 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
181 for (i = 0; i < sizeof(data); i++)
182 OSMO_ASSERT(data[i] == i);
183
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100184 printf("Hexparse with buffer too short\n");
185 memset(data, 0, sizeof(data));
186 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
187 printf("rc = %d\n", rc);
188
189 printf("Hexparse with uneven amount of digits\n");
190 memset(data, 0, sizeof(data));
191 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
192 printf("rc = %d\n", rc);
193
194 printf("Hexparse with invalid char\n");
195 memset(data, 0, sizeof(data));
196 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
197 printf("rc = %d\n", rc);
198}
199
Harald Welte7869baf2018-07-31 20:25:48 +0200200static void test_ipa_ccm_id_resp_parsing(void)
201{
202 struct tlv_parsed tvp;
203 int rc;
204
205 static const uint8_t id_resp_data[] = {
206 0x00, 0x13, IPAC_IDTAG_MACADDR,
207 '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
208 0x00, 0x11, IPAC_IDTAG_IPADDR,
209 '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
210 0x00, 0x0a, IPAC_IDTAG_UNIT,
211 '1','2','3','4','/','0','/','0','\0',
212 0x00, 0x02, IPAC_IDTAG_LOCATION1,
213 '\0',
214 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
215 'B','T','S','_','N','B','T','1','3','1','G','\0',
216 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
217 '1','6','5','a','0','2','9','_','5','5','\0',
218 0x00, 0x14, IPAC_IDTAG_SWVERSION,
219 '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
220 0x00, 0x18, IPAC_IDTAG_UNITNAME,
221 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
222 0x00, 0x0a, IPAC_IDTAG_SERNR,
223 '0','0','1','1','0','7','8','1','\0'
224 };
225
226 printf("\nTesting IPA CCM ID RESP parsing\n");
227
228 rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
229 OSMO_ASSERT(rc == 0);
230
231 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
232 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
233 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
234 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
235 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
236 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
237 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
238 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
239 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
240 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
241 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
242 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
243 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
244 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
245 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
246 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
247 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
248 OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
249 OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
250}
251
252static void test_ipa_ccm_id_get_parsing(void)
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200253{
254 struct tlv_parsed tvp;
255 int rc;
256
Harald Welte48fd0192018-07-31 20:19:49 +0200257 /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
Harald Welte7869baf2018-07-31 20:25:48 +0200258 static const uint8_t id_get_data[] = {
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200259 0x01, 0x08,
260 0x01, 0x07,
261 0x01, 0x02,
262 0x01, 0x03,
263 0x01, 0x04,
264 0x01, 0x05,
265 0x01, 0x01,
266 0x01, 0x00,
267 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
268 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
269 };
270
Harald Welte7869baf2018-07-31 20:25:48 +0200271 printf("\nTesting IPA CCM ID GET parsing\n");
272
273 rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200274 OSMO_ASSERT(rc == 0);
275
276 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
277 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
278
279 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
280 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
281
282 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
283 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
284
285 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
286 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
287
288 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
289 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
290
291 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
292 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
293
294 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
295 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
296
297 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
298 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
299
300 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
301 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
302
303 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
304 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
305
306 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
307}
308
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200309static struct {
310 const char *str;
311 int min_digits;
312 int max_digits;
313 bool require_even;
314 bool expect_ok;
315} test_hexstrs[] = {
316 { NULL, 0, 10, false, true },
317 { NULL, 1, 10, false, false },
318 { "", 0, 10, false, true },
319 { "", 1, 10, false, false },
320 { " ", 0, 10, false, false },
321 { "1", 0, 10, false, true },
322 { "1", 1, 10, false, true },
323 { "1", 1, 10, true, false },
324 { "1", 2, 10, false, false },
325 { "123", 1, 10, false, true },
326 { "123", 1, 10, true, false },
327 { "123", 4, 10, false, false },
328 { "1234", 4, 10, true, true },
329 { "12345", 4, 10, true, false },
330 { "123456", 4, 10, true, true },
331 { "1234567", 4, 10, true, false },
332 { "12345678", 4, 10, true, true },
333 { "123456789", 4, 10, true, false },
334 { "123456789a", 4, 10, true, true },
335 { "123456789ab", 4, 10, true, false },
336 { "123456789abc", 4, 10, true, false },
337 { "123456789ab", 4, 10, false, false },
338 { "123456789abc", 4, 10, false, false },
339 { "0123456789abcdefABCDEF", 0, 100, false, true },
340 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
341 { "foobar", 0, 100, false, false },
342 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
343 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
344 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
345};
346
347bool test_is_hexstr()
348{
349 int i;
350 bool pass = true;
351 bool ok = true;
352 printf("\n----- %s\n", __func__);
353
354 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
355 ok = osmo_is_hexstr(test_hexstrs[i].str,
356 test_hexstrs[i].min_digits,
357 test_hexstrs[i].max_digits,
358 test_hexstrs[i].require_even);
359 pass = pass && (ok == test_hexstrs[i].expect_ok);
360 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
361 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
362 test_hexstrs[i].str,
363 test_hexstrs[i].min_digits,
364 test_hexstrs[i].max_digits,
365 test_hexstrs[i].require_even,
366 test_hexstrs[i].expect_ok ? "valid" : "invalid");
367 }
368 return pass;
369}
370
Harald Welte504caac2017-10-27 17:19:59 +0200371struct bcdcheck {
372 uint8_t bcd;
373 char ch;
374};
375
376static const struct bcdcheck bcdchecks[] = {
377 { 0, '0' },
378 { 1, '1' },
379 { 2, '2' },
380 { 3, '3' },
381 { 4, '4' },
382 { 5, '5' },
383 { 6, '6' },
384 { 7, '7' },
385 { 8, '8' },
386 { 9, '9' },
387 { 0xA, 'A' },
388 { 0xB, 'B' },
389 { 0xC, 'C' },
390 { 0xD, 'D' },
391 { 0xE, 'E' },
392 { 0xF, 'F' },
393};
394
395static void bcd_test(void)
396{
397 int i;
398
399 printf("\nTesting BCD conversion\n");
400 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
401 const struct bcdcheck *check = &bcdchecks[i];
402 char ch = osmo_bcd2char(check->bcd);
403 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
404 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
405 /* test char -> bcd back-coversion */
406 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
407 /* test for lowercase hex char */
408 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
409 }
410}
411
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100412struct bcd2str_test {
413 const char *bcd_hex;
414 int start_nibble;
415 int end_nibble;
416 bool allow_hex;
417 size_t str_size;
418 const char *expect_str;
419 int expect_rc;
420};
421
422static const struct bcd2str_test bcd2str_tests[] = {
423 {
424 .bcd_hex = "1a 32 54 76 98 f0",
425 .start_nibble = 1,
426 .end_nibble = 11,
427 .expect_str = "1234567890",
428 .expect_rc = 10,
429 },
430 {
431 .bcd_hex = "1a 32 a4 cb 9d f0",
432 .start_nibble = 1,
433 .end_nibble = 11,
434 .expect_str = "1234ABCD90",
435 .expect_rc = -EINVAL,
436 },
437 {
438 .bcd_hex = "1a 32 a4 cb 9d f0",
439 .start_nibble = 1,
440 .end_nibble = 11,
441 .allow_hex = true,
442 .expect_str = "1234ABCD90",
443 .expect_rc = 10,
444 },
445 {
446 .bcd_hex = "1a 32 54 76 98 f0",
447 .start_nibble = 1,
448 .end_nibble = 12,
449 .expect_str = "1234567890F",
450 .expect_rc = -EINVAL,
451 },
452 {
453 .bcd_hex = "1a 32 54 76 98 f0",
454 .start_nibble = 1,
455 .end_nibble = 12,
456 .allow_hex = true,
457 .expect_str = "1234567890F",
458 .expect_rc = 11,
459 },
460 {
461 .bcd_hex = "1a 32 54 76 98 f0",
462 .start_nibble = 0,
463 .end_nibble = 12,
464 .allow_hex = true,
465 .expect_str = "A1234567890F",
466 .expect_rc = 12,
467 },
468 {
469 .bcd_hex = "1a 32 54 76 98 f0",
470 .start_nibble = 1,
471 .end_nibble = 12,
472 .str_size = 5,
473 .expect_str = "1234",
474 .expect_rc = 11,
475 },
476 {
477 .bcd_hex = "",
478 .start_nibble = 1,
479 .end_nibble = 1,
480 .expect_str = "",
481 .expect_rc = 0,
482 },
483};
484
485static void bcd2str_test(void)
486{
487 int i;
488 uint8_t bcd[64];
489 int rc;
490
491 printf("\nTesting bcd to string conversion\n");
492
493 for (i = 0; i < ARRAY_SIZE(bcd2str_tests); i++) {
494 const struct bcd2str_test *t = &bcd2str_tests[i];
495 char str[64] = {};
496 size_t str_size = t->str_size ? : sizeof(str);
497
498 osmo_hexparse(t->bcd_hex, bcd, sizeof(bcd));
499
500 printf("- BCD-input='%s' nibbles=[%d..%d[ str_size=%zu\n", t->bcd_hex,
501 t->start_nibble, t->end_nibble, str_size);
502 rc = osmo_bcd2str(str, str_size, bcd, t->start_nibble, t->end_nibble, t->allow_hex);
503
504 printf(" rc=%d\n", rc);
505
506 OSMO_ASSERT(str[str_size-1] == '\0');
507 printf(" -> %s\n", osmo_quote_str(str, -1));
508
509 if (rc != t->expect_rc)
510 printf(" ERROR: expected rc=%d\n", t->expect_rc);
511 if (strcmp(str, t->expect_str))
512 printf(" ERROR: expected result %s\n", osmo_quote_str(t->expect_str, -1));
513 }
514
515 printf("- zero output buffer\n");
516 rc = osmo_bcd2str(NULL, 100, bcd, 1, 2, false);
517 printf(" bcd2str(NULL, ...) -> %d\n", rc);
518 OSMO_ASSERT(rc < 0);
519 rc = osmo_bcd2str((char*)23, 0, bcd, 1, 2, false);
520 printf(" bcd2str(dst, 0, ...) -> %d\n", rc);
521 OSMO_ASSERT(rc < 0);
522}
523
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100524static void str_escape_test(void)
525{
526 int i;
527 int j;
528 uint8_t in_buf[32];
529 char out_buf[11];
530 const char *printable = "printable";
531 const char *res;
532
533 printf("\nTesting string escaping\n");
534 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100535 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100536 for (j = 0; j < 16; j++) {
537 for (i = 0; i < 16; i++)
538 in_buf[i] = (j << 4) | i;
539 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
540 }
541
542 printf("- nul terminated:\n");
543 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
544
545 printf("- passthru:\n");
546 res = osmo_escape_str(printable, -1);
547 if (res != printable)
548 printf("NOT passed through! \"%s\"\n", res);
549 else
550 printf("passed through unchanged \"%s\"\n", res);
551
552 printf("- zero length:\n");
553 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
554
555 printf("- truncation when too long:\n");
556 memset(in_buf, 'x', sizeof(in_buf));
557 in_buf[0] = '\a';
558 in_buf[7] = 'E';
559 memset(out_buf, 0x7f, sizeof(out_buf));
560 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
561 OSMO_ASSERT(out_buf[10] == 0x7f);
562
563 printf("- passthrough without truncation when no escaping needed:\n");
564 memset(in_buf, 'x', sizeof(in_buf));
565 in_buf[19] = 'E';
566 in_buf[20] = '\0';
567 memset(out_buf, 0x7f, sizeof(out_buf));
568 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, -1, out_buf, 10));
569 OSMO_ASSERT(out_buf[0] == 0x7f);
570}
571
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200572static void str_quote_test(void)
573{
574 int i;
575 int j;
576 uint8_t in_buf[32];
577 char out_buf[11];
578 const char *printable = "printable";
579 const char *res;
580
581 printf("\nTesting string quoting\n");
582 printf("- all chars from 0 to 255 in batches of 16:\n");
583 in_buf[16] = '\0';
584 for (j = 0; j < 16; j++) {
585 for (i = 0; i < 16; i++)
586 in_buf[i] = (j << 4) | i;
587 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
588 }
589
590 printf("- nul terminated:\n");
591 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
592
593 printf("- never passthru:\n");
594 res = osmo_quote_str(printable, -1);
595 if (res != printable)
596 printf("NOT passed through. '%s'\n", res);
597 else
598 printf("passed through unchanged '%s'\n", res);
599
600 printf("- zero length:\n");
601 printf("'%s'\n", osmo_quote_str("omitted", 0));
602
603 printf("- truncation when too long:\n");
604 memset(in_buf, 'x', sizeof(in_buf));
605 in_buf[0] = '\a';
606 in_buf[5] = 'E';
607 memset(out_buf, 0x7f, sizeof(out_buf));
608 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
609 OSMO_ASSERT(out_buf[10] == 0x7f);
610
611 printf("- always truncation, even when no escaping needed:\n");
612 memset(in_buf, 'x', sizeof(in_buf));
613 in_buf[6] = 'E'; /* dst has 10, less 2 quotes and nul, leaves 7, i.e. in[6] is last */
614 in_buf[20] = '\0';
615 memset(out_buf, 0x7f, sizeof(out_buf));
616 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
617 OSMO_ASSERT(out_buf[0] == '"');
618
619 printf("- try to feed too little buf for quoting:\n");
620 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
621
622 printf("- NULL string becomes a \"NULL\" literal:\n");
623 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
624}
625
Harald Welte15a5f8d2018-06-06 16:58:17 +0200626static void isqrt_test(void)
627{
628 int i;
629
630 printf("\nTesting integer square-root\n");
631 srand(time(NULL));
632 for (i = 0; i < 1024; i++) {
633 uint16_t x;
634 uint32_t r = rand();
635 if (RAND_MAX < UINT16_MAX)
636 x = r * (UINT16_MAX/RAND_MAX);
637 else
638 x = r;
Neels Hofmeyr6979c542018-07-19 22:05:21 +0200639 uint32_t sq = (uint32_t)x*x;
Harald Welte15a5f8d2018-06-06 16:58:17 +0200640 uint32_t y = osmo_isqrt32(sq);
641 if (y != x)
642 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
643 }
644}
645
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200646
647struct osmo_sockaddr_to_str_and_uint_test_case {
648 uint16_t port;
649 bool omit_port;
650 const char *addr;
651 unsigned int addr_len;
652 bool omit_addr;
653 unsigned int expect_rc;
654 const char *expect_returned_addr;
655};
656
657struct osmo_sockaddr_to_str_and_uint_test_case osmo_sockaddr_to_str_and_uint_test_data[] = {
658 {
659 .port = 0,
660 .addr = "0.0.0.0",
661 .addr_len = 20,
662 .expect_rc = 7,
663 },
664 {
665 .port = 65535,
666 .addr = "255.255.255.255",
667 .addr_len = 20,
668 .expect_rc = 15,
669 },
670 {
671 .port = 1234,
672 .addr = "234.23.42.123",
673 .addr_len = 20,
674 .expect_rc = 13,
675 },
676 {
677 .port = 1234,
678 .addr = "234.23.42.123",
679 .addr_len = 10,
680 .expect_rc = 13,
681 .expect_returned_addr = "234.23.42",
682 },
683 {
684 .port = 1234,
685 .omit_port = true,
686 .addr = "234.23.42.123",
687 .addr_len = 20,
688 .expect_rc = 13,
689 },
690 {
691 .port = 1234,
692 .addr = "234.23.42.123",
693 .omit_addr = true,
694 .expect_rc = 0,
695 .expect_returned_addr = "",
696 },
697 {
698 .port = 1234,
699 .addr = "234.23.42.123",
700 .addr_len = 0,
701 .expect_rc = 13,
702 .expect_returned_addr = "",
703 },
704 {
705 .port = 1234,
706 .addr = "234.23.42.123",
707 .omit_port = true,
708 .omit_addr = true,
709 .expect_rc = 0,
710 .expect_returned_addr = "",
711 },
712};
713
714static void osmo_sockaddr_to_str_and_uint_test(void)
715{
716 int i;
717 printf("\n%s\n", __func__);
718
719 for (i = 0; i < ARRAY_SIZE(osmo_sockaddr_to_str_and_uint_test_data); i++) {
720 struct osmo_sockaddr_to_str_and_uint_test_case *t =
721 &osmo_sockaddr_to_str_and_uint_test_data[i];
722
723 struct sockaddr_in sin = {
724 .sin_family = AF_INET,
725 .sin_port = htons(t->port),
726 };
727 inet_aton(t->addr, &sin.sin_addr);
728
729 char addr[20] = {};
730 uint16_t port = 0;
731 unsigned int rc;
732
733 rc = osmo_sockaddr_to_str_and_uint(
734 t->omit_addr? NULL : addr, t->addr_len,
735 t->omit_port? NULL : &port,
736 (const struct sockaddr*)&sin);
737
738 printf("[%d] %s:%u%s%s addr_len=%u --> %s:%u rc=%u\n",
739 i,
740 t->addr ? : "-",
741 t->port,
742 t->omit_addr ? " (omit addr)" : "",
743 t->omit_port ? " (omit port)" : "",
744 t->addr_len,
745 addr, port, rc);
746 if (rc != t->expect_rc)
747 printf("ERROR: Expected rc = %u\n", t->expect_rc);
748 if (!t->expect_returned_addr)
749 t->expect_returned_addr = t->addr;
750 if (strcmp(t->expect_returned_addr, addr))
751 printf("ERROR: Expected addr = '%s'\n", t->expect_returned_addr);
752 if (!t->omit_port && port != t->port)
753 printf("ERROR: Expected port = %u\n", t->port);
754 }
755}
756
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200757struct osmo_str_tolowupper_test_data {
758 const char *in;
759 bool use_static_buf;
760 size_t buflen;
761 const char *expect_lower;
762 const char *expect_upper;
763 size_t expect_rc;
764 size_t expect_rc_inplace;
765};
766
767struct osmo_str_tolowupper_test_data osmo_str_tolowupper_tests[] = {
768 {
769 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
770 .use_static_buf = true,
771 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
772 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
773 },
774 {
775 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
776 .buflen = 99,
777 .expect_lower = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz!@#$%^&*()",
778 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
779 .expect_rc = 62,
780 .expect_rc_inplace = 62,
781 },
782 {
783 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
784 .buflen = 0,
785 .expect_lower = "Unset",
786 .expect_upper = "Unset",
787 .expect_rc = 62,
788 .expect_rc_inplace = 0,
789 },
790 {
791 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
792 .buflen = 1,
793 .expect_lower = "",
794 .expect_upper = "",
795 .expect_rc = 62,
796 .expect_rc_inplace = 0,
797 },
798 {
799 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
800 .buflen = 2,
801 .expect_lower = "a",
802 .expect_upper = "A",
803 .expect_rc = 62,
804 .expect_rc_inplace = 1,
805 },
806 {
807 .in = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()",
808 .buflen = 28,
809 .expect_lower = "abcdefghijklmnopqrstuvwxyza",
810 .expect_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZA",
811 .expect_rc = 62,
812 .expect_rc_inplace = 27,
813 },
814};
815
816
817static void osmo_str_tolowupper_test()
818{
819 int i;
820 char buf[128];
821 bool ok = true;
822 printf("\n%s\n", __func__);
823
824 for (i = 0; i < ARRAY_SIZE(osmo_str_tolowupper_tests); i++) {
825 struct osmo_str_tolowupper_test_data *d = &osmo_str_tolowupper_tests[i];
826 size_t rc = 0;
827 const char *res;
828
829 /* tolower */
830 if (d->use_static_buf) {
831 res = osmo_str_tolower(d->in);
832 printf("osmo_str_tolower(%s)\n", osmo_quote_str(d->in, -1));
833 printf(" = %s\n", osmo_quote_str(res, -1));
834 } else {
835 OSMO_ASSERT(sizeof(buf) >= d->buflen);
836 osmo_strlcpy(buf, "Unset", sizeof(buf));
837 rc = osmo_str_tolower_buf(buf, d->buflen, d->in);
838 res = buf;
839 printf("osmo_str_tolower_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
840 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
841 }
842
843 if (strcmp(res, d->expect_lower)) {
844 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
845 " got %s\n", i, osmo_quote_str(res, -1));
846 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
847 ok = false;
848 }
849
850 if (!d->use_static_buf && d->expect_rc != rc) {
851 printf("ERROR: osmo_str_tolowupper_test[%d] tolower\n"
852 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
853 ok = false;
854 }
855
856 /* tolower, in-place */
857 if (!d->use_static_buf) {
858 osmo_strlcpy(buf,
859 d->buflen ? d->in : "Unset",
860 sizeof(buf));
861 rc = osmo_str_tolower_buf(buf, d->buflen, buf);
862 res = buf;
863 printf("osmo_str_tolower_buf(%zu, %s, in-place)\n",
864 d->buflen, osmo_quote_str(d->in, -1));
865 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
866
867 if (strcmp(res, d->expect_lower)) {
868 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
869 " got %s\n", i, osmo_quote_str(res, -1));
870 printf(" expected %s\n", osmo_quote_str(d->expect_lower, -1));
871 ok = false;
872 }
873
874 if (d->expect_rc_inplace != rc) {
875 printf("ERROR: osmo_str_tolowupper_test[%d] tolower in-place\n"
876 " got rc=%zu, expected rc=%zu\n",
877 i, rc, d->expect_rc_inplace);
878 ok = false;
879 }
880 }
881
882 /* toupper */
883 if (d->use_static_buf) {
884 res = osmo_str_toupper(d->in);
885 printf("osmo_str_toupper(%s)\n", osmo_quote_str(d->in, -1));
886 printf(" = %s\n", osmo_quote_str(res, -1));
887 } else {
888 OSMO_ASSERT(sizeof(buf) >= d->buflen);
889 osmo_strlcpy(buf, "Unset", sizeof(buf));
890 rc = osmo_str_toupper_buf(buf, d->buflen, d->in);
891 res = buf;
892 printf("osmo_str_toupper_buf(%zu, %s)\n", d->buflen, osmo_quote_str(d->in, -1));
893 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
894 }
895
896 if (strcmp(res, d->expect_upper)) {
897 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
898 " got %s\n", i, osmo_quote_str(res, -1));
899 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
900 ok = false;
901 }
902
903 if (!d->use_static_buf && d->expect_rc != rc) {
904 printf("ERROR: osmo_str_tolowupper_test[%d] toupper\n"
905 " got rc=%zu, expected rc=%zu\n", i, rc, d->expect_rc);
906 ok = false;
907 }
908
909 /* toupper, in-place */
910 if (!d->use_static_buf) {
911 osmo_strlcpy(buf,
912 d->buflen ? d->in : "Unset",
913 sizeof(buf));
914 rc = osmo_str_toupper_buf(buf, d->buflen, buf);
915 res = buf;
916 printf("osmo_str_toupper_buf(%zu, %s, in-place)\n",
917 d->buflen, osmo_quote_str(d->in, -1));
918 printf(" = %zu, %s\n", rc, osmo_quote_str(res, -1));
919
920 if (strcmp(res, d->expect_upper)) {
921 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
922 " got %s\n", i, osmo_quote_str(res, -1));
923 printf(" expected %s\n", osmo_quote_str(d->expect_upper, -1));
924 ok = false;
925 }
926
927 if (d->expect_rc_inplace != rc) {
928 printf("ERROR: osmo_str_tolowupper_test[%d] toupper in-place\n"
929 " got rc=%zu, expected rc=%zu\n",
930 i, rc, d->expect_rc_inplace);
931 ok = false;
932 }
933 }
934 }
935
936 OSMO_ASSERT(ok);
937}
938
939
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100940int main(int argc, char **argv)
941{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200942 static const struct log_info log_info = {};
943 log_init(&log_info, NULL);
944
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100945 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100946 hexparse_test();
Harald Welte7869baf2018-07-31 20:25:48 +0200947 test_ipa_ccm_id_get_parsing();
948 test_ipa_ccm_id_resp_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200949 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +0200950 bcd_test();
Neels Hofmeyr7079e692018-12-05 21:02:36 +0100951 bcd2str_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100952 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200953 str_quote_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +0200954 isqrt_test();
Neels Hofmeyr59f4caf2018-07-19 22:13:19 +0200955 osmo_sockaddr_to_str_and_uint_test();
Neels Hofmeyr7c749892018-09-07 03:01:38 +0200956 osmo_str_tolowupper_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100957 return 0;
958}