blob: 24e44cf3f23d76f25fede5b49f224ac22d3c65fc [file] [log] [blame]
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -04001#include <stdio.h>
2#include <stdlib.h>
3#include <inttypes.h>
4
5#include <openbsc/gprs_llc.h>
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +02006#include <openbsc/gprs_utils.h>
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -04007
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +01008#include <openbsc/gprs_gsup_messages.h>
9
Jacob Erlbeck0572ee02015-01-12 11:14:18 +010010#include <openbsc/debug.h>
11
12#include <osmocom/core/application.h>
13
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -040014#define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); }
15#define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); }
16
Jacob Erlbeck0572ee02015-01-12 11:14:18 +010017#define VERBOSE_FPRINTF(...)
18
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -040019/**
20 * GSM 04.64 8.4.2 Receipt of unacknowledged information
21 */
22static int nu_is_retransmission(uint16_t nu, uint16_t vur)
23{
24 int ret = gprs_llc_is_retransmit(nu, vur);
25 printf("N(U) = %d, V(UR) = %d => %s\n", nu, vur,
26 ret == 1 ? "retransmit" : "new");
27 return ret;
28}
29
30static void test_8_4_2()
31{
32 printf("Testing gprs_llc_is_retransmit.\n");
33
34 ASSERT_FALSE(nu_is_retransmission(0, 0));
35 ASSERT_TRUE (nu_is_retransmission(0, 1));
36
37 /* expect 1... check for retransmissions */
38 ASSERT_TRUE (nu_is_retransmission(0, 1));
39 ASSERT_TRUE (nu_is_retransmission(511, 1));
40 ASSERT_TRUE (nu_is_retransmission(483, 1));
41 ASSERT_TRUE (nu_is_retransmission(482, 1));
42 ASSERT_FALSE(nu_is_retransmission(481, 1));
43
44 /* expect 511... check for retransmissions */
45 ASSERT_FALSE(nu_is_retransmission(0, 240)); // ahead
46 ASSERT_FALSE(nu_is_retransmission(0, 511)); // ahead
47 ASSERT_FALSE(nu_is_retransmission(1, 511)); // ahead
48 ASSERT_FALSE(nu_is_retransmission(511, 511)); // same
49 ASSERT_TRUE (nu_is_retransmission(510, 511)); // behind
50 ASSERT_TRUE (nu_is_retransmission(481, 511)); // behind
51 ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped
52}
53
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +020054static void apn_round_trip(const uint8_t *input, size_t len, const char *wanted_output)
55{
56 char output[len ? len : 1];
57 uint8_t encoded[len + 50];
58 char *out_str;
59 int enc_len;
60
61 /* decode and verify we have what we want */
62 out_str = gprs_apn_to_str(output, input, len);
63 OSMO_ASSERT(out_str);
64 OSMO_ASSERT(out_str == &output[0]);
65 OSMO_ASSERT(strlen(out_str) == strlen(wanted_output));
66 OSMO_ASSERT(strcmp(out_str, wanted_output) == 0);
67
68 /* encode and verify it */
69 if (len != 0) {
70 enc_len = gprs_str_to_apn(encoded, ARRAY_SIZE(encoded), wanted_output);
71 OSMO_ASSERT(enc_len == len);
72 OSMO_ASSERT(memcmp(encoded, input, enc_len) == 0);
73 } else {
74 enc_len = gprs_str_to_apn(encoded, 0, wanted_output);
75 OSMO_ASSERT(enc_len == -1);
76 }
77}
78
79static void test_gsm_03_03_apn(void)
80{
81
82 {
83 /* test invalid writes */
84 const uint8_t ref[10] = { 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF };
85 uint8_t output[10];
86 int enc_len;
87
88 memcpy(output, ref, ARRAY_SIZE(output));
89 enc_len = gprs_str_to_apn(output, 0, "");
90 OSMO_ASSERT(enc_len == -1);
91 OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
92
93 memcpy(output, ref, ARRAY_SIZE(output));
94 enc_len = gprs_str_to_apn(output, 0, "foo");
95 OSMO_ASSERT(enc_len == -1);
96 OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
97
98 memcpy(output, ref, ARRAY_SIZE(output));
99 enc_len = gprs_str_to_apn(output, 1, "foo");
100 OSMO_ASSERT(enc_len == -1);
101 OSMO_ASSERT(memcmp(ref + 1, output + 1, ARRAY_SIZE(ref) - 1) == 0);
102
103 memcpy(output, ref, ARRAY_SIZE(output));
104 enc_len = gprs_str_to_apn(output, 2, "foo");
105 OSMO_ASSERT(enc_len == -1);
106 OSMO_ASSERT(memcmp(ref + 2, output + 2, ARRAY_SIZE(ref) - 2) == 0);
107
108 memcpy(output, ref, ARRAY_SIZE(output));
109 enc_len = gprs_str_to_apn(output, 3, "foo");
110 OSMO_ASSERT(enc_len == -1);
111 OSMO_ASSERT(memcmp(ref + 3, output + 3, ARRAY_SIZE(ref) - 3) == 0);
112 }
113
114 {
115 /* single empty label */
116 uint8_t input[] = { 0x0 };
117 const char *output = "";
118 apn_round_trip(input, ARRAY_SIZE(input), output);
119 }
120
121 {
122 /* no label */
123 uint8_t input[] = { };
124 const char *output = "";
125 apn_round_trip(input, ARRAY_SIZE(input), output);
126 }
127
128 {
129 /* single label with A */
130 uint8_t input[] = { 0x1, 65 };
131 const char *output = "A";
132 apn_round_trip(input, ARRAY_SIZE(input), output);
133 OSMO_ASSERT(gprs_apn_to_str(NULL, input, ARRAY_SIZE(input) - 1) == NULL);
134 }
135
136 {
137 uint8_t input[] = { 0x3, 65, 66, 67, 0x2, 90, 122 };
138 const char *output = "ABC.Zz";
139 char tmp[strlen(output) + 1];
140 apn_round_trip(input, ARRAY_SIZE(input), output);
141 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 1) == NULL);
142 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 2) == NULL);
143 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 4) == NULL);
144 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 5) == NULL);
145 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 6) == NULL);
146 }
147}
148
Harald Welte50f1c0a2016-04-25 19:01:26 +0200149/* Tests for osmo_gsup_messages.c */
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100150
151#define TEST_IMSI_IE 0x01, 0x08, 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0xf5
152#define TEST_IMSI_STR "123456789012345"
153
154static void test_gsup_messages_dec_enc(void)
155{
156 int test_idx;
157 int rc;
Jacob Erlbeck0572ee02015-01-12 11:14:18 +0100158 uint8_t buf[1024];
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100159
160 static const uint8_t send_auth_info_req[] = {
161 0x08,
162 TEST_IMSI_IE
163 };
164
165 static const uint8_t send_auth_info_err[] = {
166 0x09,
167 TEST_IMSI_IE,
168 0x02, 0x01, 0x07 /* GPRS no allowed */
169 };
170
171 static const uint8_t send_auth_info_res[] = {
172 0x0a,
173 TEST_IMSI_IE,
174 0x03, 0x22, /* Auth tuple */
175 0x20, 0x10,
176 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
177 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
178 0x21, 0x04,
179 0x21, 0x22, 0x23, 0x24,
180 0x22, 0x08,
181 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
182 0x03, 0x22, /* Auth tuple */
183 0x20, 0x10,
184 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
185 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
186 0x21, 0x04,
187 0xa1, 0xa2, 0xa3, 0xa4,
188 0x22, 0x08,
189 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
190 };
191
192 static const uint8_t update_location_req[] = {
193 0x04,
194 TEST_IMSI_IE,
195 };
196
197 static const uint8_t update_location_err[] = {
198 0x05,
199 TEST_IMSI_IE,
200 0x02, 0x01, 0x07 /* GPRS no allowed */
201 };
202
203 static const uint8_t update_location_res[] = {
204 0x06,
205 TEST_IMSI_IE,
Holger Hans Peter Freytherb927f1c2015-04-22 23:09:41 -0400206 0x08, 0x07, /* MSISDN of the subscriber */
207 0x91, 0x94, 0x61, 0x46, 0x32, 0x24, 0x43,
Holger Hans Peter Freyther0bb56742015-05-17 19:56:38 +0200208 0x09, 0x07, /* HLR-Number of the subscriber */
209 0x91, 0x83, 0x52, 0x38, 0x48, 0x83, 0x93,
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100210 0x04, 0x00, /* PDP info complete */
Holger Hans Peter Freyther49c1a712015-04-23 09:13:01 -0400211 0x05, 0x15,
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100212 0x10, 0x01, 0x01,
213 0x11, 0x02, 0xf1, 0x21, /* IPv4 */
214 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n',
Holger Hans Peter Freyther49c1a712015-04-23 09:13:01 -0400215 0x13, 0x01, 0x02,
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100216 0x05, 0x11,
217 0x10, 0x01, 0x02,
218 0x11, 0x02, 0xf1, 0x21, /* IPv4 */
219 0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n',
220 };
221
222 static const uint8_t location_cancellation_req[] = {
223 0x1c,
224 TEST_IMSI_IE,
225 0x06, 0x01, 0x00,
226 };
227
228 static const uint8_t location_cancellation_err[] = {
229 0x1d,
230 TEST_IMSI_IE,
231 0x02, 0x01, 0x03 /* Illegal MS */
232 };
233
234 static const uint8_t location_cancellation_res[] = {
235 0x1e,
236 TEST_IMSI_IE,
237 };
238
Jacob Erlbeck69d27132015-01-15 11:50:08 +0100239 static const uint8_t purge_ms_req[] = {
240 0x0c,
241 TEST_IMSI_IE,
242 };
243
244 static const uint8_t purge_ms_err[] = {
Jacob Erlbeck85ba6552015-01-29 14:15:54 +0100245 0x0d,
Jacob Erlbeck69d27132015-01-15 11:50:08 +0100246 TEST_IMSI_IE,
247 0x02, 0x01, 0x03, /* Illegal MS */
248 };
249
250 static const uint8_t purge_ms_res[] = {
Jacob Erlbeck85ba6552015-01-29 14:15:54 +0100251 0x0e,
Jacob Erlbeck69d27132015-01-15 11:50:08 +0100252 TEST_IMSI_IE,
253 0x07, 0x00,
254 };
255
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100256 static const struct test {
257 char *name;
258 const uint8_t *data;
259 size_t data_len;
260 } test_messages[] = {
261 {"Send Authentication Info Request",
262 send_auth_info_req, sizeof(send_auth_info_req)},
263 {"Send Authentication Info Error",
264 send_auth_info_err, sizeof(send_auth_info_err)},
265 {"Send Authentication Info Result",
266 send_auth_info_res, sizeof(send_auth_info_res)},
267 {"Update Location Request",
268 update_location_req, sizeof(update_location_req)},
269 {"Update Location Error",
270 update_location_err, sizeof(update_location_err)},
271 {"Update Location Result",
272 update_location_res, sizeof(update_location_res)},
273 {"Location Cancellation Request",
274 location_cancellation_req, sizeof(location_cancellation_req)},
275 {"Location Cancellation Error",
276 location_cancellation_err, sizeof(location_cancellation_err)},
277 {"Location Cancellation Result",
278 location_cancellation_res, sizeof(location_cancellation_res)},
Jacob Erlbeck69d27132015-01-15 11:50:08 +0100279 {"Purge MS Request",
280 purge_ms_req, sizeof(purge_ms_req)},
281 {"Purge MS Error",
282 purge_ms_err, sizeof(purge_ms_err)},
283 {"Purge MS Result",
284 purge_ms_res, sizeof(purge_ms_res)},
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100285 };
286
287 printf("Test GSUP message decoding/encoding\n");
288
289 for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
290 const struct test *t = &test_messages[test_idx];
291 struct gprs_gsup_message gm = {0};
292 struct msgb *msg = msgb_alloc(4096, "gsup_test");
293
294 printf(" Testing %s\n", t->name);
295
296 rc = gprs_gsup_decode(t->data, t->data_len, &gm);
297 OSMO_ASSERT(rc >= 0);
298
299 gprs_gsup_encode(msg, &gm);
300
301 fprintf(stderr, " generated message: %s\n", msgb_hexdump(msg));
302 fprintf(stderr, " original message: %s\n", osmo_hexdump(t->data, t->data_len));
303 fprintf(stderr, " IMSI: %s\n", gm.imsi);
304 OSMO_ASSERT(strcmp(gm.imsi, TEST_IMSI_STR) == 0);
305 OSMO_ASSERT(msgb_length(msg) == t->data_len);
306 OSMO_ASSERT(memcmp(msgb_data(msg), t->data, t->data_len) == 0);
307
308 msgb_free(msg);
309 }
Jacob Erlbeck0572ee02015-01-12 11:14:18 +0100310
311 /* simple truncation test */
312 for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
313 int j;
314 const struct test *t = &test_messages[test_idx];
315 int ie_end = t->data_len;
316 struct gprs_gsup_message gm = {0};
317 int counter = 0;
318 int parse_err = 0;
319
320 for (j = t->data_len - 1; j >= 0; --j) {
321 rc = gprs_gsup_decode(t->data, j, &gm);
322 counter += 1;
323
324 VERBOSE_FPRINTF(stderr,
325 " partial message decoding: "
326 "orig_len = %d, trunc = %d, rc = %d, ie_end = %d\n",
327 t->data_len, j, rc, ie_end);
328 if (rc >= 0) {
329 VERBOSE_FPRINTF(stderr,
330 " remaing partial message: %s\n",
331 osmo_hexdump(t->data + j, ie_end - j));
332
333 OSMO_ASSERT(j <= ie_end - 2);
334 OSMO_ASSERT(t->data[j+0] <= GPRS_GSUP_KC_IE);
335 OSMO_ASSERT(t->data[j+1] <= ie_end - j - 2);
336
337 ie_end = j;
338 } else {
339 parse_err += 1;
340 }
341 }
342
343 fprintf(stderr,
344 " message %d: tested %d truncations, %d parse failures\n",
345 test_idx, counter, parse_err);
346 }
347
348 /* message modification test (relies on ASAN or valgrind being used) */
349 for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
350 int j;
351 const struct test *t = &test_messages[test_idx];
352 struct gprs_gsup_message gm = {0};
353 uint8_t val;
354 int counter = 0;
355 int parse_err = 0;
356
357 OSMO_ASSERT(sizeof(buf) >= t->data_len);
358
359 for (j = t->data_len - 1; j >= 0; --j) {
360 memcpy(buf, t->data, t->data_len);
361 val = 0;
362 do {
363 VERBOSE_FPRINTF(stderr,
364 "t = %d, len = %d, val = %d\n",
365 test_idx, j, val);
366 buf[j] = val;
367 rc = gprs_gsup_decode(buf, t->data_len, &gm);
368 counter += 1;
369 if (rc < 0)
370 parse_err += 1;
371
372 val += 1;
373 } while (val != (uint8_t)256);
374 }
375
376 fprintf(stderr,
377 " message %d: tested %d modifications, %d parse failures\n",
378 test_idx, counter, parse_err);
379 }
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100380}
381
Jacob Erlbeck79af67d2015-01-19 08:27:34 +0100382static void test_gprs_timer_enc_dec(void)
383{
384 int i, u, secs, tmr;
385 const int upper_secs_test_limit = 12000;
386 int dec_secs, last_dec_secs = -1;
387
388 printf("Test GPRS timer decoding/encoding\n");
389
390 /* Check gprs_tmr_to_secs with all 256 encoded values */
391 for (u = 0; u <= GPRS_TMR_DEACTIVATED; u += 32) {
392 fprintf(stderr, "Testing decoding with timer value unit %u\n",
393 u / 32);
394 for (i = 0; i < 32; i++) {
395 switch (u) {
396 case GPRS_TMR_2SECONDS:
397 OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 2 * i);
398 break;
399
400 default:
401 case GPRS_TMR_MINUTE:
402 OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 60 * i);
403 break;
404
405 case GPRS_TMR_6MINUTE:
406 OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 360 * i);
407 break;
408
409 case GPRS_TMR_DEACTIVATED:
410 OSMO_ASSERT(gprs_tmr_to_secs(u + i) == -1);
411 break;
412 }
413
414 OSMO_ASSERT(gprs_tmr_to_secs(u + i) < upper_secs_test_limit);
415 }
416 }
417
418 /* Check gprs_secs_to_tmr_floor for secs that can exactly be
419 * represented as GPRS timer values */
420 for (i = 0; i < GPRS_TMR_DEACTIVATED; i++) {
421 int j;
422 secs = gprs_tmr_to_secs(i);
423 tmr = gprs_secs_to_tmr_floor(secs);
424 OSMO_ASSERT(secs == gprs_tmr_to_secs(tmr));
425
426 /* Check that the highest resolution is used */
427 for (j = 0; j < tmr; j++)
428 OSMO_ASSERT(secs != gprs_tmr_to_secs(j));
429 }
430 OSMO_ASSERT(GPRS_TMR_DEACTIVATED == gprs_secs_to_tmr_floor(-1));
431
432 /* Check properties of gprs_secs_to_tmr_floor */
433 for (secs = 0; secs <= upper_secs_test_limit; secs++) {
434 int tmr = gprs_secs_to_tmr_floor(secs);
435 int delta_secs = gprs_tmr_to_secs((tmr & ~0x1f) | 1);
436 dec_secs = gprs_tmr_to_secs(tmr);
437
438 /* Check floor */
439 OSMO_ASSERT(dec_secs <= secs);
440 /* Check monotonicity */
441 OSMO_ASSERT(dec_secs >= last_dec_secs);
442 /* Check max distance (<= resolution) */
443 OSMO_ASSERT(dec_secs - last_dec_secs <= delta_secs);
444
445 last_dec_secs = dec_secs;
446 }
447}
448
Jacob Erlbeck0572ee02015-01-12 11:14:18 +0100449const struct log_info_cat default_categories[] = {
450 [DGPRS] = {
451 .name = "DGPRS",
452 .description = "GPRS Packet Service",
453 .enabled = 0, .loglevel = LOGL_DEBUG,
454 },
455};
456
457static struct log_info info = {
458 .cat = default_categories,
459 .num_cat = ARRAY_SIZE(default_categories),
460};
461
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -0400462int main(int argc, char **argv)
463{
Jacob Erlbeck0572ee02015-01-12 11:14:18 +0100464 osmo_init_logging(&info);
465
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -0400466 test_8_4_2();
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200467 test_gsm_03_03_apn();
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100468 test_gsup_messages_dec_enc();
Jacob Erlbeck79af67d2015-01-19 08:27:34 +0100469 test_gprs_timer_enc_dec();
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -0400470
471 printf("Done.\n");
472 return EXIT_SUCCESS;
473}