blob: d3b334f3b9b02b31ad6919fbeca35229f8f37c78 [file] [log] [blame]
Holger Hans Peter Freytherac967702009-07-29 07:37:48 +02001/*
2 * SCCP testing code
3 *
4 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2009 by on-waves.com
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 General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <stdio.h>
26
27#include <arpa/inet.h>
28
29#include <sccp/sccp.h>
30#include <openbsc/gsm_data.h>
31#include <openbsc/debug.h>
32
33#define MIN(x, y) ((x) < (y) ? (x) : (y))
34
35/* BSC -> MSC */
36static const u_int8_t bssmap_reset[] = {
37 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
38 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
39 0x01, 0x20,
40};
41
42/* MSC -> BSC reset ack */
43static const u_int8_t bssmap_reset_ack[] = {
44 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
45 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
46 0x00, 0x01, 0x31,
47};
48
49/* MSC -> BSC paging, connection less */
50static const u_int8_t bssmap_paging[] = {
51 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
52 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
53 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10,
54 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06,
55};
56
57/* MSC -> BSC paging, UDT without PC */
58static const u_int8_t bssmap_udt[] = {
59 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
60 0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08,
61 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97,
62 0x61, 0x1a, 0x01, 0x06,
63};
64
65/* BSC -> MSC connection open */
66static const u_int8_t bssmap_cr[] = {
67 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02,
68 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05,
69 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3,
70 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33,
71 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01,
72 0x31, 0x97, 0x61, 0x00
73};
74
75/* MSC -> BSC connection confirm */
76static const u_int8_t bssmap_cc[] = {
77 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
78};
79
80/* MSC -> BSC DTAP
81 *
82 * we fake a bit and make it BSC -> MSC... so the
83 * payload does not make any sense..
84 */
85static const u_int8_t bssmap_dtap[] = {
86 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c,
87 0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13,
88 0x45, 0xf4,
89};
90
91/* MSC -> BSC clear command */
92static const u_int8_t bssmap_clear[] = {
93 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20,
94 0x04, 0x01, 0x09,
95};
96
97/* MSC -> BSC released */
98static const u_int8_t bssmap_released[] = {
99 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f,
100 0x02, 0x23, 0x42, 0x00,
101};
102
103/* BSC -> MSC released */
104static const u_int8_t bssmap_release_complete[] = {
105 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03
106};
107
108struct test_data {
109 int length;
110 const u_int8_t *data;
111 int payload_start;
112 int payload_length;
113 u_int8_t first_byte;
114
115 /* in case it should trigger a sccp response */
116 int write;
117 const u_int8_t *response;
118 int response_length;
119};
120
121static const struct test_data test_data[] = {
122 {
123 .length = ARRAY_SIZE(bssmap_reset),
124 .data = &bssmap_reset[0],
125 .payload_start = 12,
126 .payload_length = ARRAY_SIZE(bssmap_reset) - 12,
127 .first_byte = 0x0,
128 },
129 {
130 .length = ARRAY_SIZE(bssmap_reset_ack),
131 .data = &bssmap_reset_ack[0],
132 .payload_start = 16,
133 .payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16,
134 .first_byte = 0x0,
135 },
136 {
137 .length = ARRAY_SIZE(bssmap_paging),
138 .data = &bssmap_paging[0],
139 .payload_start = 16,
140 .payload_length = ARRAY_SIZE(bssmap_paging) - 16,
141 .first_byte = 0x0,
142 },
143 {
144 .length = ARRAY_SIZE(bssmap_cr),
145 .data = &bssmap_cr[0],
146 .payload_start = 12,
147 /* 0x00 is end of optional data, subtract this byte */
148 .payload_length = 31,
149 .first_byte = 0x0,
150
151 /* the connection request should trigger a connection confirm */
152 .write = 1,
153 .response = &bssmap_cc[0],
154 .response_length= ARRAY_SIZE(bssmap_cc),
155 },
156 {
157 .length = ARRAY_SIZE(bssmap_dtap),
158 .data = &bssmap_dtap[0],
159 .payload_start = 7,
160 .payload_length = 15,
161 .first_byte = 0x01,
162 },
163 {
164 .length = ARRAY_SIZE(bssmap_clear),
165 .data = &bssmap_clear[0],
166 .payload_start = 7,
167 .payload_length = 6,
168 .first_byte = 0x00,
169 },
170 {
171 .length = ARRAY_SIZE(bssmap_released),
172 .data = &bssmap_released[0],
173 .payload_length = 2,
174 .payload_start = 11,
175 .first_byte = 0x23,
176
177 .write = 1,
178 .response = &bssmap_release_complete[0],
179 .response_length= ARRAY_SIZE(bssmap_release_complete),
180 },
181};
182
183/* we will send UDTs and verify they look like this */
184static const struct test_data send_data[] = {
185 {
186 .length = ARRAY_SIZE(bssmap_udt),
187 .data = &bssmap_udt[0],
188 .payload_start = 12,
189 .payload_length = ARRAY_SIZE(bssmap_udt) - 12,
190 .first_byte = 0x0,
191 },
192 {
193 .length = ARRAY_SIZE(bssmap_reset),
194 .data = &bssmap_reset[0],
195 .payload_start = 12,
196 .payload_length = ARRAY_SIZE(bssmap_reset) - 12,
197 .first_byte = 0x0,
198 },
199};
200
201struct connection_test {
202 /* should the connection be refused? */
203 int refuse;
204
205 int with_data;
206
207 /* on which side to close the connection? */
208 int close_side;
209 int close_cause;
210};
211
212/* sccp connection handling we want to test */
213static const struct connection_test connection_tests[] = {
214 {
215 .refuse = 1,
216 },
217 {
218 .refuse = 1,
219 .with_data = 1,
220 },
221 {
222 .refuse = 0,
223 .close_side = 0,
224 .close_cause = 5,
225 },
226 {
227 .refuse = 0,
228 .close_side = 0,
229 .close_cause = 5,
230 .with_data = 1,
231 },
232 {
233 .refuse = 0,
234 .close_side = 1,
235 .close_cause = 5,
236 },
237 {
238 .refuse = 0,
239 .close_side = 1,
240 .close_cause = 5,
241 .with_data = 1,
242 },
243};
244
245/* testing procedure:
246 * - we will use sccp_write and see what will be set in the
247 * outgoing callback
248 * - we will call sccp_system_incoming and see which calls
249 * are made. And then compare it to the ones we expect. We
250 * want the payload to arrive, or callbacks to be called.
251 * - we will use sccp_connection_socket and sccp_connection_write
252 * and verify state handling of connections
253 */
254
255static int current_test;
256
257/*
258 * test state...
259 */
260static int called = 0;
261static int matched = 0;
262static int write_called = 0;
263
264#define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args)
265
266/*
267 * writing these packets and expecting a result
268 */
269int sccp_read_cb(struct msgb *data, unsigned len, void *context)
270{
271 u_int16_t payload_length = test_data[current_test].payload_length;
272 const u_int8_t *got, *wanted;
273 int i;
274
275 called = 1;
276
277 if (msgb_l3len(data) < len) {
278 /* this should never be reached */
279 FAIL("Something horrible happened.. invalid packet..\n");
280 exit(-1);
281 }
282
283 if (len == 0 || len != payload_length) {
284 FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length);
285 return -1;
286 }
287
288 if (data->l3h[0] != test_data[current_test].first_byte) {
289 FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n",
290 data->l3h[0], test_data[current_test].first_byte);
291 return -1;
292 }
293
294 got = &data->l3h[0];
295 wanted = test_data[current_test].data + test_data[current_test].payload_start;
296
297 for (i = 0; i < len; ++i) {
298 if (got[i] != wanted[i]) {
299 FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
300 got[i], wanted[i], i);
301 return -1;
302 }
303 }
304
305 matched = 1;
306 return 0;
307}
308
309int sccp_write_cb(struct msgb *data, void *ctx)
310{
311 int i = 0;
312 const u_int8_t *got, *wanted;
313
314 if (test_data[current_test].response == NULL) {
315 FAIL("Didn't expect write callback\n");
316 return -1;
317 } else if (test_data[current_test].response_length != msgb_l2len(data)) {
318 FAIL("Size does not match. Got: %d Wanted: %d\n",
319 msgb_l2len(data), test_data[current_test].response_length);
320 }
321
322 got = &data->l2h[0];
323 wanted = test_data[current_test].response;
324
325 for (i = 0; i < msgb_l2len(data); ++i) {
326 if (got[i] != wanted[i]) {
327 FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
328 got[i], wanted[i], i);
329 return -1;
330 }
331 }
332
333 write_called = 1;
334 return 0;
335}
336
337void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len)
338{
339 sccp_read_cb(msgb, len, connection->data_ctx);
340}
341
342void sccp_c_state(struct sccp_connection *connection, int old_state)
343{
344 if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE)
345 sccp_connection_free(connection);
346}
347
348int sccp_accept_cb(struct sccp_connection *connection, void *user_data)
349{
350 called = 1;
351 unsigned int ref = 0;
352 ref |= connection->destination_local_reference.octet1 << 24;
353 ref |= connection->destination_local_reference.octet2 << 16;
354 ref |= connection->destination_local_reference.octet3 << 8;
355 ref = ntohl(ref);
356
357 connection->data_cb = sccp_c_read;
358 connection->state_cb = sccp_c_state;
359
360 /* accept this */
361 return 0;
362}
363
364static int sccp_udt_write_cb(struct msgb *data, void *context)
365{
366 const u_int8_t *got, *wanted;
367 int i;
368
369 write_called = 1;
370
371 if (send_data[current_test].length != msgb_l2len(data)) {
372 FAIL("Size does not match. Got: %d Wanted: %d\n",
373 msgb_l2len(data), send_data[current_test].length);
374 return -1;
375 }
376
377 got = &data->l2h[0];
378 wanted = send_data[current_test].data;
379
380 for (i = 0; i < msgb_l2len(data); ++i) {
381 if (got[i] != wanted[i]) {
382 FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
383 got[i], wanted[i], i);
384 return -1;
385 }
386 }
387
388 matched = 1;
389 return 0;
390}
391
392static void test_sccp_system(void)
393{
394 sccp_system_init(sccp_write_cb, NULL);
395 sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
396 sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
397
398 for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
399 unsigned int length = test_data[current_test].length;
400 struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
401 msg->l2h = msgb_put(msg, length);
402 memcpy(msg->l2h, test_data[current_test].data, length);
403
404 called = matched = write_called = 0;
405 printf("Testing packet: %d\n", current_test);
406 sccp_system_incoming(msg);
407
408 if (!called || !matched || (test_data[current_test].write != write_called))
409 FAIL("current test: %d called: %d matched: %d write: %d\n",
410 current_test, called, matched, write_called);
411
412 msgb_free(msg);
413 }
414}
415
416/* test sending of udt */
417static void test_sccp_send_udt(void)
418{
419 sccp_system_init(sccp_udt_write_cb, NULL);
420 sccp_set_read(NULL, NULL, NULL);
421 sccp_connection_set_incoming(NULL, NULL, NULL);
422
423 for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) {
424 const struct test_data *test = &send_data[current_test];
425
426 struct msgb *msg = msgb_alloc(test->payload_length, __func__);
427 msg->l3h = msgb_put(msg, test->payload_length);
428 memcpy(msg->l3h, test->data + test->payload_start, test->payload_length);
429
430 matched = write_called = 0;
431 printf("Testing packet: %d\n", current_test);
432 sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
433
434 if (!matched || !write_called)
435 FAIL("current test: %d matched: %d write: %d\n",
436 current_test, matched, write_called);
437
438 msgb_free(msg);
439 }
440}
441
442/* send udt from one end to another */
443static unsigned int test_value = 0x2442;
444static int sccp_udt_read(struct msgb *data, unsigned int len, void *context)
445{
446 unsigned int *val;
447
448 if (len != 4) {
449 FAIL("Wrong size: %d\n", msgb_l3len(data));
450 return -1;
451 }
452
453 val = (unsigned int*)data->l3h;
454 matched = test_value == *val;
455
456 return 0;
457}
458
459static int sccp_write_loop(struct msgb *data, void *context)
460{
461 /* send it back to us */
462 sccp_system_incoming(data);
463 return 0;
464}
465
466static void test_sccp_udt_communication(void)
467{
468 struct msgb *data;
469 unsigned int *val;
470
471 sccp_system_init(sccp_write_loop, NULL);
472 sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL);
473 sccp_connection_set_incoming(NULL, NULL, NULL);
474
475
476 data = msgb_alloc(4, "test data");
477 data->l3h = &data->data[0];
478 val = (unsigned int *)msgb_put(data, 4);
479 *val = test_value;
480
481 matched = 0;
482 sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
483
484 if (!matched)
485 FAIL("Talking with us didn't work\n");
486
487 msgb_free(data);
488}
489
490
491/* connection testing... open, send, close */
492static const struct connection_test *current_con_test;
493static struct sccp_connection *outgoing_con;
494static struct sccp_connection *incoming_con;
495static int outgoing_data, incoming_data, incoming_state, outgoing_state;
496
497static struct msgb *test_data1, *test_data2, *test_data3;
498
499static void sccp_conn_in_state(struct sccp_connection *conn, int old_state)
500{
501 printf("\tincome: %d -> %d\n", old_state, conn->connection_state);
502 if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
503 if (conn == incoming_con) {
504 sccp_connection_free(conn);
505 incoming_con = NULL;
506 }
507 }
508}
509
510static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
511{
512 /* compare the data */
513 ++incoming_data;
514 printf("\tincoming data: %d\n", len);
515
516 /* compare the data */
517 if (len != 4) {
518 FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
519 return;
520 }
521
522 if (incoming_data == 1) {
523 if (memcmp(msg->l3h, test_data1->l3h, len) != 0) {
524 FAIL("Comparing the data failed: %d\n", incoming_data);
525 incoming_state = 0;
526 printf("Got: %s\n", hexdump(msg->l3h, len));
527 printf("Wanted: %s\n", hexdump(test_data1->l3h, len));
528
529 }
530 } else if (incoming_data == 2) {
531 if (memcmp(msg->l3h, test_data2->l3h, len) != 0) {
532 FAIL("Comparing the data failed: %d\n", incoming_data);
533 incoming_state = 0;
534 printf("Got: %s\n", hexdump(msg->l3h, len));
535 printf("Wanted: %s\n", hexdump(test_data2->l3h, len));
536 }
537 }
538
539 /* sending out data */
540 if (incoming_data == 2) {
541 printf("\tReturning data3\n");
542 sccp_connection_write(conn, test_data3);
543 }
544}
545
546static int sccp_conn_accept(struct sccp_connection *conn, void *ctx)
547{
548 printf("\taccept: %p\n", conn);
549 conn->state_cb = sccp_conn_in_state;
550 conn->data_cb = sccp_conn_in_data;
551
552 if (current_con_test->refuse)
553 return -1;
554
555 incoming_con = conn;
556 return 0;
557}
558
559/* callbacks for the outgoing side */
560static void sccp_conn_out_state(struct sccp_connection *conn, int old_state)
561{
562 printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state);
563
564 if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
565 if (conn == outgoing_con) {
566 sccp_connection_free(conn);
567 outgoing_con = NULL;
568 }
569 }
570}
571
572static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
573{
574 ++outgoing_data;
575 printf("\toutgoing data: %p %d\n", conn, len);
576
577 if (len != 4)
578 FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
579
580 if (outgoing_data == 1) {
581 if (memcmp(msg->l3h, test_data3->l3h, len) != 0) {
582 FAIL("Comparing the data failed\n");
583 outgoing_state = 0;
584 }
585 }
586}
587
588static void do_test_sccp_connection(const struct connection_test *test)
589{
590 int ret;
591
592 current_con_test = test;
593 outgoing_con = incoming_con = 0;
594
595 outgoing_con = sccp_connection_socket();
596 if (!outgoing_con) {
597 FAIL("Connection is NULL\n");
598 return;
599 }
600
601 outgoing_con->state_cb = sccp_conn_out_state;
602 outgoing_con->data_cb = sccp_conn_out_data;
603 outgoing_data = incoming_data = 0;
604 incoming_state = outgoing_state = 1;
605
606 /* start testing */
607 if (test->with_data) {
608 if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0)
609 FAIL("Binding failed\n");
610 } else {
611 ++incoming_data;
612 if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0)
613 FAIL("Binding failed\n");
614 }
615
616 if (test->refuse) {
617 if (outgoing_con)
618 FAIL("Outgoing connection should have been refused.\n");
619 } else {
620 if (!incoming_con)
621 FAIL("Creating incoming didn't work.\n");
622
623 printf("\tWriting test data2\n");
624 sccp_connection_write(outgoing_con, test_data2);
625
626 /* closing connection */
627 if (test->close_side == 0)
628 ret = sccp_connection_close(outgoing_con, 0);
629 else
630 ret = sccp_connection_close(incoming_con, 0);
631
632 if (ret != 0)
633 FAIL("Closing the connection failed\n");
634 }
635
636 /* outgoing should be gone now */
637 if (outgoing_con)
638 FAIL("Outgoing connection was not properly closed\n");
639
640 if (incoming_con)
641 FAIL("Incoming connection was not propery closed.\n");
642
643 if (test->refuse == 0) {
644 if (outgoing_data != 1 || incoming_data != 2) {
645 FAIL("Data sending failed: %d/%d %d/%d\n",
646 outgoing_data, 1,
647 incoming_data, 2);
648 }
649 }
650
651 if (!incoming_state || !outgoing_state)
652 FAIL("Failure with the state transition. %d %d\n",
653 outgoing_state, incoming_state);
654}
655
656static void test_sccp_connection(void)
657{
658 sccp_system_init(sccp_write_loop, NULL);
659 sccp_set_read(NULL, NULL, NULL);
660 sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL);
661
662 test_data1 = msgb_alloc(4, "data1");
663 test_data1->l3h = msgb_put(test_data1, 4);
664 *((unsigned int*)test_data1->l3h) = 0x23421122;
665
666 test_data2 = msgb_alloc(4, "data2");
667 test_data2->l3h = msgb_put(test_data2, 4);
668 *((unsigned int*)test_data2->l3h) = 0x42232211;
669
670 test_data3 = msgb_alloc(4, "data3");
671 test_data3->l3h = msgb_put(test_data3, 4);
672 *((unsigned int*)test_data3->l3h) = 0x2323ff55;
673
674
675 for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) {
676 printf("Testing %d refuse: %d with_data: %d\n",
677 current_test, connection_tests[current_test].refuse,
678 connection_tests[current_test].with_data);
679 do_test_sccp_connection(&connection_tests[current_test]);
680 }
681
682 msgb_free(test_data1);
683 msgb_free(test_data2);
684 msgb_free(test_data3);
685}
686
687/* invalid input */
688static void test_sccp_system_crash(void)
689{
690 printf("trying to provoke a crash with invalid input\n");
691 sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
692 sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
693
694 for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
695 int original_length = test_data[current_test].length;
696 int length = original_length + 2;
697 int i;
698
699 printf("Testing packet: %d\n", current_test);
700
701 for (i = length; i >= 0; --i) {
702 unsigned int length = MIN(test_data[current_test].length, i);
703 struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
704 msg->l2h = msgb_put(msg, length);
705 memcpy(msg->l2h, test_data[current_test].data, length);
706 sccp_system_incoming(msg);
707 msgb_free(msg);
708 }
709 }
710
711 printf("survived\n");
712}
713
714
715int main(int argc, char **argv)
716{
717 test_sccp_system();
718 test_sccp_send_udt();
719 test_sccp_udt_communication();
720 test_sccp_connection();
721 test_sccp_system_crash();
722 return 0;
723}