blob: bf7697db82aa0fc6f89af5e9f80b9e02eac27c9f [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
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -040010#define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); }
11#define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); }
12
13/**
14 * GSM 04.64 8.4.2 Receipt of unacknowledged information
15 */
16static int nu_is_retransmission(uint16_t nu, uint16_t vur)
17{
18 int ret = gprs_llc_is_retransmit(nu, vur);
19 printf("N(U) = %d, V(UR) = %d => %s\n", nu, vur,
20 ret == 1 ? "retransmit" : "new");
21 return ret;
22}
23
24static void test_8_4_2()
25{
26 printf("Testing gprs_llc_is_retransmit.\n");
27
28 ASSERT_FALSE(nu_is_retransmission(0, 0));
29 ASSERT_TRUE (nu_is_retransmission(0, 1));
30
31 /* expect 1... check for retransmissions */
32 ASSERT_TRUE (nu_is_retransmission(0, 1));
33 ASSERT_TRUE (nu_is_retransmission(511, 1));
34 ASSERT_TRUE (nu_is_retransmission(483, 1));
35 ASSERT_TRUE (nu_is_retransmission(482, 1));
36 ASSERT_FALSE(nu_is_retransmission(481, 1));
37
38 /* expect 511... check for retransmissions */
39 ASSERT_FALSE(nu_is_retransmission(0, 240)); // ahead
40 ASSERT_FALSE(nu_is_retransmission(0, 511)); // ahead
41 ASSERT_FALSE(nu_is_retransmission(1, 511)); // ahead
42 ASSERT_FALSE(nu_is_retransmission(511, 511)); // same
43 ASSERT_TRUE (nu_is_retransmission(510, 511)); // behind
44 ASSERT_TRUE (nu_is_retransmission(481, 511)); // behind
45 ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped
46}
47
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +020048static void apn_round_trip(const uint8_t *input, size_t len, const char *wanted_output)
49{
50 char output[len ? len : 1];
51 uint8_t encoded[len + 50];
52 char *out_str;
53 int enc_len;
54
55 /* decode and verify we have what we want */
56 out_str = gprs_apn_to_str(output, input, len);
57 OSMO_ASSERT(out_str);
58 OSMO_ASSERT(out_str == &output[0]);
59 OSMO_ASSERT(strlen(out_str) == strlen(wanted_output));
60 OSMO_ASSERT(strcmp(out_str, wanted_output) == 0);
61
62 /* encode and verify it */
63 if (len != 0) {
64 enc_len = gprs_str_to_apn(encoded, ARRAY_SIZE(encoded), wanted_output);
65 OSMO_ASSERT(enc_len == len);
66 OSMO_ASSERT(memcmp(encoded, input, enc_len) == 0);
67 } else {
68 enc_len = gprs_str_to_apn(encoded, 0, wanted_output);
69 OSMO_ASSERT(enc_len == -1);
70 }
71}
72
73static void test_gsm_03_03_apn(void)
74{
75
76 {
77 /* test invalid writes */
78 const uint8_t ref[10] = { 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF };
79 uint8_t output[10];
80 int enc_len;
81
82 memcpy(output, ref, ARRAY_SIZE(output));
83 enc_len = gprs_str_to_apn(output, 0, "");
84 OSMO_ASSERT(enc_len == -1);
85 OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
86
87 memcpy(output, ref, ARRAY_SIZE(output));
88 enc_len = gprs_str_to_apn(output, 0, "foo");
89 OSMO_ASSERT(enc_len == -1);
90 OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0);
91
92 memcpy(output, ref, ARRAY_SIZE(output));
93 enc_len = gprs_str_to_apn(output, 1, "foo");
94 OSMO_ASSERT(enc_len == -1);
95 OSMO_ASSERT(memcmp(ref + 1, output + 1, ARRAY_SIZE(ref) - 1) == 0);
96
97 memcpy(output, ref, ARRAY_SIZE(output));
98 enc_len = gprs_str_to_apn(output, 2, "foo");
99 OSMO_ASSERT(enc_len == -1);
100 OSMO_ASSERT(memcmp(ref + 2, output + 2, ARRAY_SIZE(ref) - 2) == 0);
101
102 memcpy(output, ref, ARRAY_SIZE(output));
103 enc_len = gprs_str_to_apn(output, 3, "foo");
104 OSMO_ASSERT(enc_len == -1);
105 OSMO_ASSERT(memcmp(ref + 3, output + 3, ARRAY_SIZE(ref) - 3) == 0);
106 }
107
108 {
109 /* single empty label */
110 uint8_t input[] = { 0x0 };
111 const char *output = "";
112 apn_round_trip(input, ARRAY_SIZE(input), output);
113 }
114
115 {
116 /* no label */
117 uint8_t input[] = { };
118 const char *output = "";
119 apn_round_trip(input, ARRAY_SIZE(input), output);
120 }
121
122 {
123 /* single label with A */
124 uint8_t input[] = { 0x1, 65 };
125 const char *output = "A";
126 apn_round_trip(input, ARRAY_SIZE(input), output);
127 OSMO_ASSERT(gprs_apn_to_str(NULL, input, ARRAY_SIZE(input) - 1) == NULL);
128 }
129
130 {
131 uint8_t input[] = { 0x3, 65, 66, 67, 0x2, 90, 122 };
132 const char *output = "ABC.Zz";
133 char tmp[strlen(output) + 1];
134 apn_round_trip(input, ARRAY_SIZE(input), output);
135 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 1) == NULL);
136 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 2) == NULL);
137 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 4) == NULL);
138 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 5) == NULL);
139 OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 6) == NULL);
140 }
141}
142
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100143/* TODO: Move tlv testing to libosmocore */
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100144static void check_tlv_parse(uint8_t **data, size_t *data_len,
145 uint8_t exp_tag, size_t exp_len, const uint8_t *exp_val)
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100146{
147 uint8_t *value;
148 size_t value_len;
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100149 uint8_t tag;
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100150 int rc;
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100151 uint8_t *saved_data = *data;
152 size_t saved_data_len = *data_len;
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100153
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100154 rc = gprs_match_tlv(data, data_len, exp_tag ^ 1, NULL, NULL);
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100155 OSMO_ASSERT(rc == 0);
156
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100157 rc = gprs_match_tlv(data, data_len, exp_tag, &value, &value_len);
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100158 OSMO_ASSERT(rc == (int)value_len + 2);
159 OSMO_ASSERT(value_len == exp_len);
160 OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0);
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100161
162 /* restore data/data_len */
163 *data = saved_data;
164 *data_len = saved_data_len;
165
166 rc = gprs_shift_tlv(data, data_len, &tag, &value, &value_len);
167 OSMO_ASSERT(rc == (int)value_len + 2);
168 OSMO_ASSERT(tag == exp_tag);
169 OSMO_ASSERT(value_len == exp_len);
170 OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0);
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100171}
172
173static void check_tv_fixed_match(uint8_t **data, size_t *data_len,
174 uint8_t tag, size_t len, const uint8_t *exp_val)
175{
176 uint8_t *value;
177 int rc;
178
179 rc = gprs_match_tv_fixed(data, data_len, tag ^ 1, len, NULL);
180 OSMO_ASSERT(rc == 0);
181
182 rc = gprs_match_tv_fixed(data, data_len, tag, len, &value);
183 OSMO_ASSERT(rc == (int)len + 1);
184 OSMO_ASSERT(memcmp(value, exp_val, len) == 0);
185}
186
187static void check_v_fixed_shift(uint8_t **data, size_t *data_len,
188 size_t len, const uint8_t *exp_val)
189{
190 uint8_t *value;
191 int rc;
192
193 rc = gprs_shift_v_fixed(data, data_len, len, &value);
194 OSMO_ASSERT(rc == (int)len);
195 OSMO_ASSERT(memcmp(value, exp_val, len) == 0);
196}
197
198static void check_lv_shift(uint8_t **data, size_t *data_len,
199 size_t exp_len, const uint8_t *exp_val)
200{
201 uint8_t *value;
202 size_t value_len;
203 int rc;
204
205 rc = gprs_shift_lv(data, data_len, &value, &value_len);
206 OSMO_ASSERT(rc == (int)value_len + 1);
207 OSMO_ASSERT(value_len == exp_len);
208 OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0);
209}
210
211static void check_tlv_match_data_len(size_t data_len, uint8_t tag, size_t len,
212 const uint8_t *test_data)
213{
214 uint8_t buf[300] = {0};
215
216 uint8_t *unchanged_ptr = buf - 1;
217 size_t unchanged_len = 0xdead;
218 size_t tmp_data_len = data_len;
219 uint8_t *value = unchanged_ptr;
220 size_t value_len = unchanged_len;
221 uint8_t *data = buf;
222
223 OSMO_ASSERT(data_len <= sizeof(buf));
224
225 tlv_put(data, tag, len, test_data);
226 if (data_len < len + 2) {
227 OSMO_ASSERT(-1 == gprs_match_tlv(&data, &tmp_data_len,
228 tag, &value, &value_len));
229 OSMO_ASSERT(tmp_data_len == 0);
230 OSMO_ASSERT(data == buf + data_len);
231 OSMO_ASSERT(value == unchanged_ptr);
232 OSMO_ASSERT(value_len == unchanged_len);
233 } else {
234 OSMO_ASSERT(0 <= gprs_match_tlv(&data, &tmp_data_len,
235 tag, &value, &value_len));
236 OSMO_ASSERT(value != unchanged_ptr);
237 OSMO_ASSERT(value_len != unchanged_len);
238 }
239}
240
241static void check_tv_fixed_match_data_len(size_t data_len,
242 uint8_t tag, size_t len,
243 const uint8_t *test_data)
244{
245 uint8_t buf[300] = {0};
246
247 uint8_t *unchanged_ptr = buf - 1;
248 size_t tmp_data_len = data_len;
249 uint8_t *value = unchanged_ptr;
250 uint8_t *data = buf;
251
252 OSMO_ASSERT(data_len <= sizeof(buf));
253
254 tv_fixed_put(data, tag, len, test_data);
255
256 if (data_len < len + 1) {
257 OSMO_ASSERT(-1 == gprs_match_tv_fixed(&data, &tmp_data_len,
258 tag, len, &value));
259 OSMO_ASSERT(tmp_data_len == 0);
260 OSMO_ASSERT(data == buf + data_len);
261 OSMO_ASSERT(value == unchanged_ptr);
262 } else {
263 OSMO_ASSERT(0 <= gprs_match_tv_fixed(&data, &tmp_data_len,
264 tag, len, &value));
265 OSMO_ASSERT(value != unchanged_ptr);
266 }
267}
268
269static void check_v_fixed_shift_data_len(size_t data_len,
270 size_t len, const uint8_t *test_data)
271{
272 uint8_t buf[300] = {0};
273
274 uint8_t *unchanged_ptr = buf - 1;
275 size_t tmp_data_len = data_len;
276 uint8_t *value = unchanged_ptr;
277 uint8_t *data = buf;
278
279 OSMO_ASSERT(data_len <= sizeof(buf));
280
281 memcpy(data, test_data, len);
282
283 if (data_len < len) {
284 OSMO_ASSERT(-1 == gprs_shift_v_fixed(&data, &tmp_data_len,
285 len, &value));
286 OSMO_ASSERT(tmp_data_len == 0);
287 OSMO_ASSERT(data == buf + data_len);
288 OSMO_ASSERT(value == unchanged_ptr);
289 } else {
290 OSMO_ASSERT(0 <= gprs_shift_v_fixed(&data, &tmp_data_len,
291 len, &value));
292 OSMO_ASSERT(value != unchanged_ptr);
293 }
294}
295
296static void check_lv_shift_data_len(size_t data_len,
297 size_t len, const uint8_t *test_data)
298{
299 uint8_t buf[300] = {0};
300
301 uint8_t *unchanged_ptr = buf - 1;
302 size_t unchanged_len = 0xdead;
303 size_t tmp_data_len = data_len;
304 uint8_t *value = unchanged_ptr;
305 size_t value_len = unchanged_len;
306 uint8_t *data = buf;
307
308 lv_put(data, len, test_data);
309 if (data_len < len + 1) {
310 OSMO_ASSERT(-1 == gprs_shift_lv(&data, &tmp_data_len,
311 &value, &value_len));
312 OSMO_ASSERT(tmp_data_len == 0);
313 OSMO_ASSERT(data == buf + data_len);
314 OSMO_ASSERT(value == unchanged_ptr);
315 OSMO_ASSERT(value_len == unchanged_len);
316 } else {
317 OSMO_ASSERT(0 <= gprs_shift_lv(&data, &tmp_data_len,
318 &value, &value_len));
319 OSMO_ASSERT(value != unchanged_ptr);
320 OSMO_ASSERT(value_len != unchanged_len);
321 }
322}
323
324static void test_tlv_shift_functions()
325{
326 uint8_t test_data[1024];
327 uint8_t buf[1024];
328 uint8_t *data_end;
329 unsigned i, len;
330 uint8_t *data;
331 size_t data_len;
332 const uint8_t tag = 0x1a;
333
334 printf("Test shift functions\n");
335
336 for (i = 0; i < ARRAY_SIZE(test_data); i++)
337 test_data[i] = (uint8_t)i;
338
339 for (len = 0; len < 256; len++) {
340 const unsigned iterations = sizeof(buf) / (len + 2) / 4;
341
342 memset(buf, 0xee, sizeof(buf));
343 data_end = data = buf;
344
345 for (i = 0; i < iterations; i++) {
346 data_end = tlv_put(data_end, tag, len, test_data);
347 data_end = tv_fixed_put(data_end, tag, len, test_data);
348 /* v_fixed_put */
349 memcpy(data_end, test_data, len);
350 data_end += len;
351 data_end = lv_put(data_end, len, test_data);
352 }
353
354 data_len = data_end - data;
355 OSMO_ASSERT(data_len <= sizeof(buf));
356
357 for (i = 0; i < iterations; i++) {
Jacob Erlbeck697a5342014-12-11 12:05:29 +0100358 check_tlv_parse(&data, &data_len, tag, len, test_data);
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100359 check_tv_fixed_match(&data, &data_len, tag, len, test_data);
360 check_v_fixed_shift(&data, &data_len, len, test_data);
361 check_lv_shift(&data, &data_len, len, test_data);
362 }
363
364 OSMO_ASSERT(data == data_end);
365
366 /* Test at end of data */
367
368 OSMO_ASSERT(-1 == gprs_match_tlv(&data, &data_len, tag, NULL, NULL));
369 OSMO_ASSERT(-1 == gprs_match_tv_fixed(&data, &data_len, tag, len, NULL));
370 OSMO_ASSERT((len ? -1 : 0) == gprs_shift_v_fixed(&data, &data_len, len, NULL));
371 OSMO_ASSERT(-1 == gprs_shift_lv(&data, &data_len, NULL, NULL));
372
373 /* Test invalid data_len */
374 for (data_len = 0; data_len <= len + 2 + 1; data_len += 1) {
375 check_tlv_match_data_len(data_len, tag, len, test_data);
376 check_tv_fixed_match_data_len(data_len, tag, len, test_data);
377 check_v_fixed_shift_data_len(data_len, len, test_data);
378 check_lv_shift_data_len(data_len, len, test_data);
379 }
380 }
381}
382
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100383/* Tests for gprs_gsup_messages.c */
384
385#define TEST_IMSI_IE 0x01, 0x08, 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0xf5
386#define TEST_IMSI_STR "123456789012345"
387
388static void test_gsup_messages_dec_enc(void)
389{
390 int test_idx;
391 int rc;
392
393 static const uint8_t send_auth_info_req[] = {
394 0x08,
395 TEST_IMSI_IE
396 };
397
398 static const uint8_t send_auth_info_err[] = {
399 0x09,
400 TEST_IMSI_IE,
401 0x02, 0x01, 0x07 /* GPRS no allowed */
402 };
403
404 static const uint8_t send_auth_info_res[] = {
405 0x0a,
406 TEST_IMSI_IE,
407 0x03, 0x22, /* Auth tuple */
408 0x20, 0x10,
409 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
410 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
411 0x21, 0x04,
412 0x21, 0x22, 0x23, 0x24,
413 0x22, 0x08,
414 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
415 0x03, 0x22, /* Auth tuple */
416 0x20, 0x10,
417 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
418 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
419 0x21, 0x04,
420 0xa1, 0xa2, 0xa3, 0xa4,
421 0x22, 0x08,
422 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
423 };
424
425 static const uint8_t update_location_req[] = {
426 0x04,
427 TEST_IMSI_IE,
428 };
429
430 static const uint8_t update_location_err[] = {
431 0x05,
432 TEST_IMSI_IE,
433 0x02, 0x01, 0x07 /* GPRS no allowed */
434 };
435
436 static const uint8_t update_location_res[] = {
437 0x06,
438 TEST_IMSI_IE,
439 0x04, 0x00, /* PDP info complete */
440 0x05, 0x12,
441 0x10, 0x01, 0x01,
442 0x11, 0x02, 0xf1, 0x21, /* IPv4 */
443 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n',
444 0x05, 0x11,
445 0x10, 0x01, 0x02,
446 0x11, 0x02, 0xf1, 0x21, /* IPv4 */
447 0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n',
448 };
449
450 static const uint8_t location_cancellation_req[] = {
451 0x1c,
452 TEST_IMSI_IE,
453 0x06, 0x01, 0x00,
454 };
455
456 static const uint8_t location_cancellation_err[] = {
457 0x1d,
458 TEST_IMSI_IE,
459 0x02, 0x01, 0x03 /* Illegal MS */
460 };
461
462 static const uint8_t location_cancellation_res[] = {
463 0x1e,
464 TEST_IMSI_IE,
465 };
466
467 static const struct test {
468 char *name;
469 const uint8_t *data;
470 size_t data_len;
471 } test_messages[] = {
472 {"Send Authentication Info Request",
473 send_auth_info_req, sizeof(send_auth_info_req)},
474 {"Send Authentication Info Error",
475 send_auth_info_err, sizeof(send_auth_info_err)},
476 {"Send Authentication Info Result",
477 send_auth_info_res, sizeof(send_auth_info_res)},
478 {"Update Location Request",
479 update_location_req, sizeof(update_location_req)},
480 {"Update Location Error",
481 update_location_err, sizeof(update_location_err)},
482 {"Update Location Result",
483 update_location_res, sizeof(update_location_res)},
484 {"Location Cancellation Request",
485 location_cancellation_req, sizeof(location_cancellation_req)},
486 {"Location Cancellation Error",
487 location_cancellation_err, sizeof(location_cancellation_err)},
488 {"Location Cancellation Result",
489 location_cancellation_res, sizeof(location_cancellation_res)},
490 };
491
492 printf("Test GSUP message decoding/encoding\n");
493
494 for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
495 const struct test *t = &test_messages[test_idx];
496 struct gprs_gsup_message gm = {0};
497 struct msgb *msg = msgb_alloc(4096, "gsup_test");
498
499 printf(" Testing %s\n", t->name);
500
501 rc = gprs_gsup_decode(t->data, t->data_len, &gm);
502 OSMO_ASSERT(rc >= 0);
503
504 gprs_gsup_encode(msg, &gm);
505
506 fprintf(stderr, " generated message: %s\n", msgb_hexdump(msg));
507 fprintf(stderr, " original message: %s\n", osmo_hexdump(t->data, t->data_len));
508 fprintf(stderr, " IMSI: %s\n", gm.imsi);
509 OSMO_ASSERT(strcmp(gm.imsi, TEST_IMSI_STR) == 0);
510 OSMO_ASSERT(msgb_length(msg) == t->data_len);
511 OSMO_ASSERT(memcmp(msgb_data(msg), t->data, t->data_len) == 0);
512
513 msgb_free(msg);
514 }
515}
516
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -0400517int main(int argc, char **argv)
518{
519 test_8_4_2();
Holger Hans Peter Freytherce1b22e2014-08-04 14:22:13 +0200520 test_gsm_03_03_apn();
Jacob Erlbeckdcfd4562014-12-11 11:01:46 +0100521 test_tlv_shift_functions();
Jacob Erlbeckf3a271f2014-12-11 16:54:14 +0100522 test_gsup_messages_dec_enc();
Holger Hans Peter Freytherfaf1f642011-06-23 17:53:27 -0400523
524 printf("Done.\n");
525 return EXIT_SUCCESS;
526}