blob: d198424a43ed73648c66959cfeb8b560f9872062 [file] [log] [blame]
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001/*
2 * BSC NAT Message filtering
3 *
4 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2010 by On-Waves
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24
25#include <openbsc/debug.h>
26#include <openbsc/gsm_data.h>
27#include <openbsc/bsc_nat.h>
28#include <openbsc/bsc_nat_sccp.h>
29
Jonathan Santos5a45b152011-08-17 15:33:57 -040030#include <osmocom/core/application.h>
31#include <osmocom/core/talloc.h>
Jonathan Santos03fd8d02011-05-25 13:54:02 -040032
33#include <osmocom/sccp/sccp.h>
Jonathan Santos5a45b152011-08-17 15:33:57 -040034#include <osmocom/gsm/protocol/gsm_08_08.h>
Jonathan Santos03fd8d02011-05-25 13:54:02 -040035
36#include <stdio.h>
37
38/* test messages for ipa */
39static uint8_t ipa_id[] = {
40 0x00, 0x01, 0xfe, 0x06,
41};
42
43/* SCCP messages are below */
44static uint8_t gsm_reset[] = {
45 0x00, 0x12, 0xfd,
46 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
47 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
48 0x01, 0x20,
49};
50
51static const uint8_t gsm_reset_ack[] = {
52 0x00, 0x13, 0xfd,
53 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
54 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
55 0x00, 0x01, 0x31,
56};
57
58static const uint8_t gsm_paging[] = {
59 0x00, 0x20, 0xfd,
60 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
61 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
62 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10,
63 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06,
64};
65
66/* BSC -> MSC connection open */
67static const uint8_t bssmap_cr[] = {
68 0x00, 0x2c, 0xfd,
69 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02,
70 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05,
71 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3,
72 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33,
73 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01,
74 0x31, 0x97, 0x61, 0x00
75};
76
77/* MSC -> BSC connection confirm */
78static const uint8_t bssmap_cc[] = {
79 0x00, 0x0a, 0xfd,
80 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
81};
82
83/* MSC -> BSC released */
84static const uint8_t bssmap_released[] = {
85 0x00, 0x0e, 0xfd,
86 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f,
87 0x02, 0x23, 0x42, 0x00,
88};
89
90/* BSC -> MSC released */
91static const uint8_t bssmap_release_complete[] = {
92 0x00, 0x07, 0xfd,
93 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03
94};
95
96/* both directions IT timer */
97static const uint8_t connnection_it[] = {
98 0x00, 0x0b, 0xfd,
99 0x10, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03,
100 0x00, 0x00, 0x00, 0x00,
101};
102
103/* error in both directions */
104static const uint8_t proto_error[] = {
105 0x00, 0x05, 0xfd,
106 0x0f, 0x22, 0x33, 0x44, 0x00,
107};
108
109/* MGCP wrap... */
110static const uint8_t mgcp_msg[] = {
111 0x00, 0x03, 0xfc,
112 0x20, 0x20, 0x20,
113};
114
115/* location updating request */
116static const uint8_t bss_lu[] = {
117 0x00, 0x2e, 0xfd,
118 0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02,
119 0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
120 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3,
121 0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4,
122 0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50,
123 0x12, 0x03, 0x24, 0x01, 0x95, 0x00
124};
125
126/* paging response */
127static const uint8_t pag_resp[] = {
128 0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68,
129 0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f,
130 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72,
131 0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10,
132 0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08,
133 0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19,
134 0x00
135};
136
137struct filter_result {
138 const uint8_t *data;
139 const uint16_t length;
140 const int dir;
141 const int result;
142};
143
144static const struct filter_result results[] = {
145 {
146 .data = ipa_id,
147 .length = ARRAY_SIZE(ipa_id),
148 .dir = DIR_MSC,
149 .result = 1,
150 },
151 {
152 .data = gsm_reset,
153 .length = ARRAY_SIZE(gsm_reset),
154 .dir = DIR_MSC,
155 .result = 1,
156 },
157 {
158 .data = gsm_reset_ack,
159 .length = ARRAY_SIZE(gsm_reset_ack),
160 .dir = DIR_BSC,
161 .result = 1,
162 },
163 {
164 .data = gsm_paging,
165 .length = ARRAY_SIZE(gsm_paging),
166 .dir = DIR_BSC,
167 .result = 0,
168 },
169 {
170 .data = bssmap_cr,
171 .length = ARRAY_SIZE(bssmap_cr),
172 .dir = DIR_MSC,
173 .result = 0,
174 },
175 {
176 .data = bssmap_cc,
177 .length = ARRAY_SIZE(bssmap_cc),
178 .dir = DIR_BSC,
179 .result = 0,
180 },
181 {
182 .data = bssmap_released,
183 .length = ARRAY_SIZE(bssmap_released),
184 .dir = DIR_MSC,
185 .result = 0,
186 },
187 {
188 .data = bssmap_release_complete,
189 .length = ARRAY_SIZE(bssmap_release_complete),
190 .dir = DIR_BSC,
191 .result = 0,
192 },
193 {
194 .data = mgcp_msg,
195 .length = ARRAY_SIZE(mgcp_msg),
196 .dir = DIR_MSC,
197 .result = 0,
198 },
199 {
200 .data = connnection_it,
201 .length = ARRAY_SIZE(connnection_it),
202 .dir = DIR_BSC,
203 .result = 0,
204 },
205 {
206 .data = connnection_it,
207 .length = ARRAY_SIZE(connnection_it),
208 .dir = DIR_MSC,
209 .result = 0,
210 },
211 {
212 .data = proto_error,
213 .length = ARRAY_SIZE(proto_error),
214 .dir = DIR_BSC,
215 .result = 0,
216 },
217 {
218 .data = proto_error,
219 .length = ARRAY_SIZE(proto_error),
220 .dir = DIR_MSC,
221 .result = 0,
222 },
223
224};
225
226static void test_filter(void)
227{
228 int i;
229
230
231 /* start testinh with proper messages */
232 fprintf(stderr, "Testing BSS Filtering.\n");
233 for (i = 0; i < ARRAY_SIZE(results); ++i) {
234 int result;
235 struct bsc_nat_parsed *parsed;
236 struct msgb *msg = msgb_alloc(4096, "test-message");
237
238 fprintf(stderr, "Going to test item: %d\n", i);
239 memcpy(msg->data, results[i].data, results[i].length);
240 msg->l2h = msgb_put(msg, results[i].length);
241
242 parsed = bsc_nat_parse(msg);
243 if (!parsed) {
244 fprintf(stderr, "FAIL: Failed to parse the message\n");
245 continue;
246 }
247
248 result = bsc_nat_filter_ipa(results[i].dir, msg, parsed);
249 if (result != results[i].result) {
250 fprintf(stderr, "FAIL: Not the expected result got: %d wanted: %d\n",
251 result, results[i].result);
252 }
253
254 msgb_free(msg);
255 }
256}
257
258#include "bsc_data.c"
259
260static void copy_to_msg(struct msgb *msg, const uint8_t *data, unsigned int length)
261{
262 msgb_reset(msg);
263 msg->l2h = msgb_put(msg, length);
264 memcpy(msg->l2h, data, msgb_l2len(msg));
265}
266
267#define VERIFY(con_found, con, msg, ver, str) \
268 if (!con_found || con_found->bsc != con) { \
269 fprintf(stderr, "Failed to find the con: %p\n", con_found); \
270 abort(); \
271 } \
272 if (memcmp(msg->data, ver, sizeof(ver)) != 0) { \
273 fprintf(stderr, "Failed to patch the %s msg.\n", str); \
274 abort(); \
275 }
276
277/* test conn tracking once */
278static void test_contrack()
279{
280 struct bsc_nat *nat;
281 struct bsc_connection *con;
282 struct sccp_connections *con_found;
283 struct sccp_connections *rc_con;
284 struct bsc_nat_parsed *parsed;
285 struct msgb *msg;
286
287 fprintf(stderr, "Testing connection tracking.\n");
288 nat = bsc_nat_alloc();
289 con = bsc_connection_alloc(nat);
290 con->cfg = bsc_config_alloc(nat, "foo");
291 bsc_config_add_lac(con->cfg, 23);
292 bsc_config_add_lac(con->cfg, 49);
293 bsc_config_add_lac(con->cfg, 42);
294 bsc_config_del_lac(con->cfg, 49);
295 bsc_config_add_lac(con->cfg, 1111);
296 msg = msgb_alloc(4096, "test");
297
298 /* 1.) create a connection */
299 copy_to_msg(msg, bsc_cr, sizeof(bsc_cr));
300 parsed = bsc_nat_parse(msg);
301 con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
302 if (con_found != NULL) {
303 fprintf(stderr, "Con should not exist %p\n", con_found);
304 abort();
305 }
306 rc_con = create_sccp_src_ref(con, parsed);
307 if (!rc_con) {
308 fprintf(stderr, "Failed to create a ref\n");
309 abort();
310 }
311 con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
312 if (!con_found || con_found->bsc != con) {
313 fprintf(stderr, "Failed to find the con: %p\n", con_found);
314 abort();
315 }
316 if (con_found != rc_con) {
317 fprintf(stderr, "Failed to find the right connection.\n");
318 abort();
319 }
320 if (memcmp(msg->data, bsc_cr_patched, sizeof(bsc_cr_patched)) != 0) {
321 fprintf(stderr, "Failed to patch the BSC CR msg.\n");
322 abort();
323 }
324 talloc_free(parsed);
325
326 /* 2.) get the cc */
327 copy_to_msg(msg, msc_cc, sizeof(msc_cc));
328 parsed = bsc_nat_parse(msg);
329 con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
330 VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC");
331 if (update_sccp_src_ref(con_found, parsed) != 0) {
332 fprintf(stderr, "Failed to update the SCCP con.\n");
333 abort();
334 }
335
336 /* 3.) send some data */
337 copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap));
338 parsed = bsc_nat_parse(msg);
339 con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
340 VERIFY(con_found, con, msg, bsc_dtap_patched, "BSC DTAP");
341
342 /* 4.) receive some data */
343 copy_to_msg(msg, msc_dtap, sizeof(msc_dtap));
344 parsed = bsc_nat_parse(msg);
345 con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
346 VERIFY(con_found, con, msg, msc_dtap_patched, "MSC DTAP");
347
348 /* 5.) close the connection */
349 copy_to_msg(msg, msc_rlsd, sizeof(msc_rlsd));
350 parsed = bsc_nat_parse(msg);
351 con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
352 VERIFY(con_found, con, msg, msc_rlsd_patched, "MSC RLSD");
353
354 /* 6.) confirm the connection close */
355 copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
356 parsed = bsc_nat_parse(msg);
357 con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
358 if (!con_found || con_found->bsc != con) {
359 fprintf(stderr, "Failed to find the con: %p\n", con_found);
360 abort();
361 }
362 if (memcmp(msg->data, bsc_rlc_patched, sizeof(bsc_rlc_patched)) != 0) {
363 fprintf(stderr, "Failed to patch the BSC CR msg.\n");
364 abort();
365 }
366 remove_sccp_src_ref(con, msg, parsed);
367 talloc_free(parsed);
368
369 copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
370 parsed = bsc_nat_parse(msg);
371 con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
372
373 /* verify that it is gone */
374 if (con_found != NULL) {
375 fprintf(stderr, "Con should be gone. %p\n", con_found);
376 abort();
377 }
378 talloc_free(parsed);
379
380
381 bsc_config_free(con->cfg);
382 talloc_free(nat);
383 msgb_free(msg);
384}
385
386static void test_paging(void)
387{
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400388 struct bsc_nat *nat;
389 struct bsc_connection *con;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400390 struct bsc_config *cfg;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400391
392 fprintf(stderr, "Testing paging by lac.\n");
393
394 nat = bsc_nat_alloc();
395 con = bsc_connection_alloc(nat);
396 cfg = bsc_config_alloc(nat, "unknown");
397 con->cfg = cfg;
398 bsc_config_add_lac(cfg, 23);
399 con->authenticated = 1;
400 llist_add(&con->list_entry, &nat->bsc_connections);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400401
402 /* Test it by not finding it */
Jonathan Santos5a45b152011-08-17 15:33:57 -0400403 if (bsc_config_handles_lac(cfg, 8213) != 0) {
404 fprintf(stderr, "Should not be handled.\n");
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400405 abort();
406 }
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400407
408 /* Test by finding it */
409 bsc_config_del_lac(cfg, 23);
410 bsc_config_add_lac(cfg, 8213);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400411 if (bsc_config_handles_lac(cfg, 8213) == 0) {
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400412 fprintf(stderr, "Should have found it.\n");
413 abort();
414 }
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400415}
416
417static void test_mgcp_allocations(void)
418{
419#if 0
420 struct bsc_connection *bsc;
421 struct bsc_nat *nat;
422 struct sccp_connections con;
423 int i, j, multiplex;
424
425 fprintf(stderr, "Testing MGCP.\n");
426 memset(&con, 0, sizeof(con));
427
428 nat = bsc_nat_alloc();
429 nat->bsc_endpoints = talloc_zero_array(nat,
430 struct bsc_endpoint,
431 65);
432 nat->mgcp_cfg = mgcp_config_alloc();
433 nat->mgcp_cfg->trunk.number_endpoints = 64;
434
435 bsc = bsc_connection_alloc(nat);
436 bsc->cfg = bsc_config_alloc(nat, "foo");
437 bsc->cfg->max_endpoints = 60;
438 bsc_config_add_lac(bsc->cfg, 2323);
439 bsc->last_endpoint = 0x22;
440 con.bsc = bsc;
441
442 bsc_init_endps_if_needed(bsc);
443
444 i = 1;
445 do {
446 if (bsc_assign_endpoint(bsc, &con) != 0) {
447 fprintf(stderr, "failed to allocate... on iteration %d\n", i);
448 break;
449 }
450 ++i;
451 } while(1);
452
453 multiplex = bsc_mgcp_nr_multiplexes(bsc->cfg->max_endpoints);
454 for (i = 0; i < multiplex; ++i) {
455 for (j = 0; j < 32; ++j)
456 printf("%d", bsc->_endpoint_status[i*32 + j]);
457 printf(": %d of %d\n", i*32 + 32, 32 * 8);
458 }
459#endif
460}
461
462static void test_mgcp_ass_tracking(void)
463{
464 struct bsc_connection *bsc;
465 struct bsc_nat *nat;
466 struct sccp_connections con;
467 struct bsc_nat_parsed *parsed;
468 struct msgb *msg;
469
470 fprintf(stderr, "Testing MGCP.\n");
471 memset(&con, 0, sizeof(con));
472
473 nat = bsc_nat_alloc();
474 nat->bsc_endpoints = talloc_zero_array(nat,
475 struct bsc_endpoint,
476 33);
477 nat->mgcp_cfg = mgcp_config_alloc();
478 nat->mgcp_cfg->trunk.number_endpoints = 64;
479
480 bsc = bsc_connection_alloc(nat);
481 bsc->cfg = bsc_config_alloc(nat, "foo");
482 bsc_config_add_lac(bsc->cfg, 2323);
483 bsc->last_endpoint = 0x1e;
484 con.bsc = bsc;
485
486 msg = msgb_alloc(4096, "foo");
487 copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
488 parsed = bsc_nat_parse(msg);
489
490 if (msg->l2h[16] != 0 ||
491 msg->l2h[17] != 0x1) {
492 fprintf(stderr, "Input is not as expected.. %s 0x%x\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -0400493 osmo_hexdump(msg->l2h, msgb_l2len(msg)),
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400494 msg->l2h[17]);
495 abort();
496 }
497
498 if (bsc_mgcp_assign_patch(&con, msg) != 0) {
499 fprintf(stderr, "Failed to handle assignment.\n");
500 abort();
501 }
502
503 if (con.msc_endp != 1) {
504 fprintf(stderr, "Timeslot should be 1.\n");
505 abort();
506 }
507
508 if (con.bsc_endp != 0x1) {
509 fprintf(stderr, "Assigned timeslot should have been 1.\n");
510 abort();
511 }
512 if (con.bsc->_endpoint_status[0x1] != 1) {
513 fprintf(stderr, "The status on the BSC is wrong.\n");
514 abort();
515 }
516
517 int multiplex, timeslot;
518 mgcp_endpoint_to_timeslot(0x1, &multiplex, &timeslot);
519
520 uint16_t cic = htons(timeslot & 0x1f);
521 if (memcmp(&cic, &msg->l2h[16], sizeof(cic)) != 0) {
522 fprintf(stderr, "Message was not patched properly\n");
Jonathan Santos5a45b152011-08-17 15:33:57 -0400523 fprintf(stderr, "data cic: 0x%x %s\n", cic, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400524 abort();
525 }
526
527 talloc_free(parsed);
528
529 bsc_mgcp_dlcx(&con);
530 if (con.bsc_endp != -1 || con.msc_endp != -1 ||
531 con.bsc->_endpoint_status[1] != 0 || con.bsc->last_endpoint != 0x1) {
532 fprintf(stderr, "Clearing should remove the mapping.\n");
533 abort();
534 }
535
536 bsc_config_free(bsc->cfg);
537 talloc_free(nat);
538}
539
540/* test the code to find a given connection */
541static void test_mgcp_find(void)
542{
543 struct bsc_nat *nat;
544 struct bsc_connection *con;
545 struct sccp_connections *sccp_con;
546
547 fprintf(stderr, "Testing finding of a BSC Connection\n");
548
549 nat = bsc_nat_alloc();
550 con = bsc_connection_alloc(nat);
551 llist_add(&con->list_entry, &nat->bsc_connections);
552
553 sccp_con = talloc_zero(con, struct sccp_connections);
554 sccp_con->msc_endp = 12;
555 sccp_con->bsc_endp = 12;
556 sccp_con->bsc = con;
557 llist_add(&sccp_con->list_entry, &nat->sccp_connections);
558
559 if (bsc_mgcp_find_con(nat, 11) != NULL) {
560 fprintf(stderr, "Found the wrong connection.\n");
561 abort();
562 }
563
564 if (bsc_mgcp_find_con(nat, 12) != sccp_con) {
565 fprintf(stderr, "Didn't find the connection\n");
566 abort();
567 }
568
569 /* free everything */
570 talloc_free(nat);
571}
572
573static void test_mgcp_rewrite(void)
574{
575 int i;
576 struct msgb *output;
577 fprintf(stderr, "Test rewriting MGCP messages.\n");
578
579 for (i = 0; i < ARRAY_SIZE(mgcp_messages); ++i) {
580 const char *orig = mgcp_messages[i].orig;
581 const char *patc = mgcp_messages[i].patch;
582 const char *ip = mgcp_messages[i].ip;
583 const int port = mgcp_messages[i].port;
584
585 char *input = strdup(orig);
586
587 output = bsc_mgcp_rewrite(input, strlen(input), 0x1e, ip, port);
588 if (msgb_l2len(output) != strlen(patc)) {
589 fprintf(stderr, "Wrong sizes for test: %d %d != %d != %d\n", i, msgb_l2len(output), strlen(patc), strlen(orig));
590 fprintf(stderr, "String '%s' vs '%s'\n", (const char *) output->l2h, patc);
591 abort();
592 }
593
594 if (memcmp(output->l2h, patc, msgb_l2len(output)) != 0) {
595 fprintf(stderr, "Broken on %d msg: '%s'\n", i, (const char *) output->l2h);
596 abort();
597 }
598
599 msgb_free(output);
600 free(input);
601 }
602}
603
604static void test_mgcp_parse(void)
605{
606 int code, ci;
607 char transaction[60];
608
609 fprintf(stderr, "Test MGCP response parsing.\n");
610
611 if (bsc_mgcp_parse_response(crcx_resp, &code, transaction) != 0) {
612 fprintf(stderr, "Failed to parse CRCX resp.\n");
613 abort();
614 }
615
616 if (code != 200) {
617 fprintf(stderr, "Failed to parse the CODE properly. Got: %d\n", code);
618 abort();
619 }
620
621 if (strcmp(transaction, "23265295") != 0) {
622 fprintf(stderr, "Failed to parse transaction id: '%s'\n", transaction);
623 abort();
624 }
625
626 ci = bsc_mgcp_extract_ci(crcx_resp);
627 if (ci != 1) {
628 fprintf(stderr, "Failed to parse the CI. Got: %d\n", ci);
629 abort();
630 }
631}
632
633struct cr_filter {
634 const uint8_t *data;
635 int length;
636 int result;
637 int contype;
638
639 const char *bsc_imsi_allow;
640 const char *bsc_imsi_deny;
641 const char *nat_imsi_deny;
642};
643
644static struct cr_filter cr_filter[] = {
645 {
646 .data = bssmap_cr,
647 .length = sizeof(bssmap_cr),
648 .result = 1,
649 .contype = NAT_CON_TYPE_CM_SERV_REQ,
650 },
651 {
652 .data = bss_lu,
653 .length = sizeof(bss_lu),
654 .result = 1,
655 .contype = NAT_CON_TYPE_LU,
656 },
657 {
658 .data = pag_resp,
659 .length = sizeof(pag_resp),
660 .result = 1,
661 .contype = NAT_CON_TYPE_PAG_RESP,
662 },
663 {
664 /* nat deny is before blank/null BSC */
665 .data = bss_lu,
666 .length = sizeof(bss_lu),
667 .result = -3,
668 .nat_imsi_deny = "[0-9]*",
669 .contype = NAT_CON_TYPE_LU,
670 },
671 {
672 /* BSC allow is before NAT deny */
673 .data = bss_lu,
674 .length = sizeof(bss_lu),
675 .result = 1,
676 .nat_imsi_deny = "[0-9]*",
677 .bsc_imsi_allow = "2440[0-9]*",
678 .contype = NAT_CON_TYPE_LU,
679 },
680 {
681 /* BSC allow is before NAT deny */
682 .data = bss_lu,
683 .length = sizeof(bss_lu),
684 .result = 1,
685 .bsc_imsi_allow = "[0-9]*",
686 .nat_imsi_deny = "[0-9]*",
687 .contype = NAT_CON_TYPE_LU,
688 },
689 {
690 /* filter as deny is first */
691 .data = bss_lu,
692 .length = sizeof(bss_lu),
693 .result = 1,
694 .bsc_imsi_deny = "[0-9]*",
695 .bsc_imsi_allow = "[0-9]*",
696 .nat_imsi_deny = "[0-9]*",
697 .contype = NAT_CON_TYPE_LU,
698 },
699 {
700 /* deny by nat rule */
701 .data = bss_lu,
702 .length = sizeof(bss_lu),
703 .result = -3,
704 .bsc_imsi_deny = "000[0-9]*",
705 .nat_imsi_deny = "[0-9]*",
706 .contype = NAT_CON_TYPE_LU,
707 },
708 {
709 /* deny by bsc rule */
710 .data = bss_lu,
711 .length = sizeof(bss_lu),
712 .result = -2,
713 .bsc_imsi_deny = "[0-9]*",
714 .contype = NAT_CON_TYPE_LU,
715 },
716
717};
718
719static void test_cr_filter()
720{
721 int i, res, contype;
722 struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
723 struct bsc_nat_parsed *parsed;
724 struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
725 struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
726
727 struct bsc_nat *nat = bsc_nat_alloc();
728 struct bsc_connection *bsc = bsc_connection_alloc(nat);
729 bsc->cfg = bsc_config_alloc(nat, "foo");
730 bsc_config_add_lac(bsc->cfg, 1234);
731 bsc->cfg->acc_lst_name = "bsc";
732 nat->acc_lst_name = "nat";
733
734 nat_lst = bsc_nat_acc_lst_get(nat, "nat");
735 bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
736
737 bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
738 nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
739
740 for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
741 char *imsi;
742 msgb_reset(msg);
743 copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
744
745 nat_lst = bsc_nat_acc_lst_get(nat, "nat");
746 bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
747
Jonathan Santos5a45b152011-08-17 15:33:57 -0400748 if (bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400749 cr_filter[i].nat_imsi_deny ? 1 : 0,
Jonathan Santos5a45b152011-08-17 15:33:57 -0400750 &cr_filter[i].nat_imsi_deny) != 0)
751 abort();
752 if (bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400753 cr_filter[i].bsc_imsi_allow ? 1 : 0,
Jonathan Santos5a45b152011-08-17 15:33:57 -0400754 &cr_filter[i].bsc_imsi_allow) != 0)
755 abort();
756 if (bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400757 cr_filter[i].bsc_imsi_deny ? 1 : 0,
Jonathan Santos5a45b152011-08-17 15:33:57 -0400758 &cr_filter[i].bsc_imsi_deny) != 0)
759 abort();
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400760
761 parsed = bsc_nat_parse(msg);
762 if (!parsed) {
763 fprintf(stderr, "FAIL: Failed to parse the message\n");
764 abort();
765 }
766
767 res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi);
768 if (res != cr_filter[i].result) {
769 fprintf(stderr, "FAIL: Wrong result %d for test %d.\n", res, i);
770 abort();
771 }
772
773 if (contype != cr_filter[i].contype) {
774 fprintf(stderr, "FAIL: Wrong contype %d for test %d.\n", res, contype);
775 abort();
776 }
777
778 talloc_steal(parsed, imsi);
779 talloc_free(parsed);
780 }
781
782 msgb_free(msg);
783}
784
785static void test_dt_filter()
786{
787 int i;
788 struct msgb *msg = msgb_alloc(4096, "test_dt_filter");
789 struct bsc_nat_parsed *parsed;
790
791 struct bsc_nat *nat = bsc_nat_alloc();
792 struct bsc_connection *bsc = bsc_connection_alloc(nat);
793 struct sccp_connections *con = talloc_zero(0, struct sccp_connections);
794
795 bsc->cfg = bsc_config_alloc(nat, "foo");
796 bsc_config_add_lac(bsc->cfg, 23);
797 con->bsc = bsc;
798
799 msgb_reset(msg);
800 copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp));
801
802 parsed = bsc_nat_parse(msg);
803 if (!parsed) {
804 fprintf(stderr, "FAIL: Could not parse ID resp\n");
805 abort();
806 }
807
808 if (parsed->bssap != BSSAP_MSG_DTAP) {
809 fprintf(stderr, "FAIL: It should be dtap\n");
810 abort();
811 }
812
813 /* gsm_type is actually the size of the dtap */
814 if (parsed->gsm_type < msgb_l3len(msg) - 3) {
815 fprintf(stderr, "FAIL: Not enough space for the content\n");
816 abort();
817 }
818
819 if (bsc_nat_filter_dt(bsc, msg, con, parsed) != 1) {
820 fprintf(stderr, "FAIL: Should have passed..\n");
821 abort();
822 }
823
824 /* just some basic length checking... */
825 for (i = ARRAY_SIZE(id_resp); i >= 0; --i) {
826 msgb_reset(msg);
827 copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp));
828
829 parsed = bsc_nat_parse(msg);
830 if (!parsed)
831 continue;
832
833 con->imsi_checked = 0;
834 bsc_nat_filter_dt(bsc, msg, con, parsed);
835 }
836}
837
838static void test_setup_rewrite()
839{
840 struct msgb *msg = msgb_alloc(4096, "test_dt_filter");
841 struct msgb *out;
842 struct bsc_nat_parsed *parsed;
843 const char *imsi = "27408000001234";
844
845 struct bsc_nat *nat = bsc_nat_alloc();
846
847 /* a fake list */
Jonathan Santos5a45b152011-08-17 15:33:57 -0400848 struct osmo_config_list entries;
849 struct osmo_config_entry entry;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400850
851 INIT_LLIST_HEAD(&entries.entry);
852 entry.mcc = "274";
853 entry.mnc = "08";
854 entry.option = "^0([1-9])";
855 entry.text = "0049";
856 llist_add_tail(&entry.list, &entries.entry);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400857 bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400858
859 /* verify that nothing changed */
860 msgb_reset(msg);
861 copy_to_msg(msg, cc_setup_international, ARRAY_SIZE(cc_setup_international));
862 parsed = bsc_nat_parse(msg);
863 if (!parsed) {
864 fprintf(stderr, "FAIL: Could not parse ID resp\n");
865 abort();
866 }
867
Jonathan Santos5a45b152011-08-17 15:33:57 -0400868 out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400869 if (msg != out) {
870 fprintf(stderr, "FAIL: The message should not have been changed\n");
871 abort();
872 }
873
874 if (out->len != ARRAY_SIZE(cc_setup_international)) {
875 fprintf(stderr, "FAIL: Length of message changed\n");
876 abort();
877 }
878
879 if (memcmp(out->data, cc_setup_international, out->len) != 0) {
880 fprintf(stderr, "FAIL: Content modified..\n");
881 abort();
882 }
883 talloc_free(parsed);
884
885 /* verify that something in the message changes */
886 msgb_reset(msg);
887 copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
888 parsed = bsc_nat_parse(msg);
889 if (!parsed) {
890 fprintf(stderr, "FAIL: Could not parse ID resp\n");
891 abort();
892 }
893
Jonathan Santos5a45b152011-08-17 15:33:57 -0400894 out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400895 if (!out) {
896 fprintf(stderr, "FAIL: A new message should be created.\n");
897 abort();
898 }
899
900 if (msg == out) {
901 fprintf(stderr, "FAIL: The message should have changed\n");
902 abort();
903 }
904
905 if (out->len != ARRAY_SIZE(cc_setup_national_patched)) {
906 fprintf(stderr, "FAIL: Length is wrong.\n");
907 abort();
908 }
909
910 if (memcmp(cc_setup_national_patched, out->data, out->len) != 0) {
911 fprintf(stderr, "FAIL: Data is wrong.\n");
Jonathan Santos5a45b152011-08-17 15:33:57 -0400912 fprintf(stderr, "Data was: %s\n", osmo_hexdump(out->data, out->len));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400913 abort();
914 }
915
916 msgb_free(out);
917
918 /* Make sure that a wildcard is matching */
919 entry.mnc = "*";
Jonathan Santos5a45b152011-08-17 15:33:57 -0400920 bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400921 msg = msgb_alloc(4096, "test_dt_filter");
922 copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
923 parsed = bsc_nat_parse(msg);
924 if (!parsed) {
925 fprintf(stderr, "FAIL: Could not parse ID resp\n");
926 abort();
927 }
928
Jonathan Santos5a45b152011-08-17 15:33:57 -0400929 out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400930 if (!out) {
931 fprintf(stderr, "FAIL: A new message should be created.\n");
932 abort();
933 }
934
935 if (msg == out) {
936 fprintf(stderr, "FAIL: The message should have changed\n");
937 abort();
938 }
939
940 if (out->len != ARRAY_SIZE(cc_setup_national_patched)) {
941 fprintf(stderr, "FAIL: Length is wrong.\n");
942 abort();
943 }
944
945 if (memcmp(cc_setup_national_patched, out->data, out->len) != 0) {
946 fprintf(stderr, "FAIL: Data is wrong.\n");
Jonathan Santos5a45b152011-08-17 15:33:57 -0400947 fprintf(stderr, "Data was: %s\n", osmo_hexdump(out->data, out->len));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400948 abort();
949 }
950
951 msgb_free(out);
952
953 /* Make sure that a wildcard is matching */
954 entry.mnc = "09";
Jonathan Santos5a45b152011-08-17 15:33:57 -0400955 bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400956 msg = msgb_alloc(4096, "test_dt_filter");
957 copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
958 parsed = bsc_nat_parse(msg);
959 if (!parsed) {
960 fprintf(stderr, "FAIL: Could not parse ID resp\n");
961 abort();
962 }
963
Jonathan Santos5a45b152011-08-17 15:33:57 -0400964 out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400965 if (out != msg) {
966 fprintf(stderr, "FAIL: The message should be unchanged.\n");
967 abort();
968 }
969
970 if (out->len != ARRAY_SIZE(cc_setup_national)) {
971 fprintf(stderr, "FAIL: Foo\n");
972 abort();
973 }
974
975 if (memcmp(out->data, cc_setup_national, ARRAY_SIZE(cc_setup_national)) != 0) {
976 fprintf(stderr, "FAIL: The message should really be unchanged.\n");
977 abort();
978 }
979
980 msgb_free(out);
981}
982
Jonathan Santos5a45b152011-08-17 15:33:57 -0400983static void test_smsc_rewrite()
984{
985 struct msgb *msg = msgb_alloc(4096, "SMSC rewrite"), *out;
986 struct bsc_nat_parsed *parsed;
987 const char *imsi = "515039900406700";
988
989 struct bsc_nat *nat = bsc_nat_alloc();
990
991 /* a fake list */
992 struct osmo_config_list smsc_entries, dest_entries;
993 struct osmo_config_entry smsc_entry, dest_entry;
994
995 INIT_LLIST_HEAD(&smsc_entries.entry);
996 INIT_LLIST_HEAD(&dest_entries.entry);
997 smsc_entry.mcc = "^515039";
998 smsc_entry.option = "639180000105()";
999 smsc_entry.text = "6666666666667";
1000 llist_add_tail(&smsc_entry.list, &smsc_entries.entry);
1001 dest_entry.mcc = "515";
1002 dest_entry.mnc = "03";
1003 dest_entry.option = "^0049";
1004 dest_entry.text = "";
1005 llist_add_tail(&dest_entry.list, &dest_entries.entry);
1006
1007 bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, &smsc_entries);
1008 bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, &dest_entries);
1009
1010 copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite));
1011 parsed = bsc_nat_parse(msg);
1012 if (!parsed) {
1013 fprintf(stderr, "FAIL: Could not parse SMS\n");
1014 abort();
1015 }
1016
1017 out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
1018 if (out == msg) {
1019 fprintf(stderr, "FAIL: This should have changed.\n");
1020 abort();
1021 }
1022
1023 if (out->len != ARRAY_SIZE(smsc_rewrite_patched)) {
1024 fprintf(stderr, "FAIL: The size should match.\n");
1025 abort();
1026 }
1027
1028 if (memcmp(out->data, smsc_rewrite_patched, out->len) != 0) {
1029 fprintf(stderr, "FAIL: the data should be changed.\n");
1030 abort();
1031 }
1032}
1033
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001034int main(int argc, char **argv)
1035{
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001036 sccp_set_log_area(DSCCP);
Jonathan Santos5a45b152011-08-17 15:33:57 -04001037 osmo_init_logging(&log_info);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001038
1039 test_filter();
1040 test_contrack();
1041 test_paging();
1042 test_mgcp_ass_tracking();
1043 test_mgcp_find();
1044 test_mgcp_rewrite();
1045 test_mgcp_parse();
1046 test_cr_filter();
1047 test_dt_filter();
1048 test_setup_rewrite();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001049 test_smsc_rewrite();
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001050 test_mgcp_allocations();
1051 return 0;
1052}