| /* |
| * SCCP testing code |
| * |
| * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> |
| * (C) 2009 by On-Waves |
| * |
| * All Rights Reserved |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| */ |
| |
| #include <stdio.h> |
| |
| #include <arpa/inet.h> |
| |
| #include <openbsc/gsm_data.h> |
| #include <openbsc/debug.h> |
| #include <osmocore/msgb.h> |
| |
| #include <sccp/sccp.h> |
| |
| #define MIN(x, y) ((x) < (y) ? (x) : (y)) |
| |
| /* BSC -> MSC */ |
| static const u_int8_t bssmap_reset[] = { |
| 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, |
| 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, |
| 0x01, 0x20, |
| }; |
| |
| /* MSC -> BSC reset ack */ |
| static const u_int8_t bssmap_reset_ack[] = { |
| 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, |
| 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, |
| 0x00, 0x01, 0x31, |
| }; |
| |
| /* MSC -> BSC paging, connection less */ |
| static const u_int8_t bssmap_paging[] = { |
| 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, |
| 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10, |
| 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, |
| 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06, |
| }; |
| |
| /* MSC -> BSC paging, UDT without PC */ |
| static const u_int8_t bssmap_udt[] = { |
| 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, |
| 0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08, |
| 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97, |
| 0x61, 0x1a, 0x01, 0x06, |
| }; |
| |
| /* BSC -> MSC connection open */ |
| static const u_int8_t bssmap_cr[] = { |
| 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02, |
| 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, |
| 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3, |
| 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33, |
| 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, |
| 0x31, 0x97, 0x61, 0x00 |
| }; |
| |
| /* MSC -> BSC connection confirm */ |
| static const u_int8_t bssmap_cc[] = { |
| 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, |
| }; |
| |
| /* MSC -> BSC DTAP |
| * |
| * we fake a bit and make it BSC -> MSC... so the |
| * payload does not make any sense.. |
| */ |
| static const u_int8_t bssmap_dtap[] = { |
| 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c, |
| 0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13, |
| 0x45, 0xf4, |
| }; |
| |
| /* MSC -> BSC clear command */ |
| static const u_int8_t bssmap_clear[] = { |
| 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20, |
| 0x04, 0x01, 0x09, |
| }; |
| |
| /* MSC -> BSC released */ |
| static const u_int8_t bssmap_released[] = { |
| 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f, |
| 0x02, 0x23, 0x42, 0x00, |
| }; |
| |
| /* BSC -> MSC released */ |
| static const u_int8_t bssmap_release_complete[] = { |
| 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03 |
| }; |
| |
| struct test_data { |
| int length; |
| const u_int8_t *data; |
| int payload_start; |
| int payload_length; |
| u_int8_t first_byte; |
| |
| /* in case it should trigger a sccp response */ |
| int write; |
| const u_int8_t *response; |
| int response_length; |
| }; |
| |
| static const struct test_data test_data[] = { |
| { |
| .length = ARRAY_SIZE(bssmap_reset), |
| .data = &bssmap_reset[0], |
| .payload_start = 12, |
| .payload_length = ARRAY_SIZE(bssmap_reset) - 12, |
| .first_byte = 0x0, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_reset_ack), |
| .data = &bssmap_reset_ack[0], |
| .payload_start = 16, |
| .payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16, |
| .first_byte = 0x0, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_paging), |
| .data = &bssmap_paging[0], |
| .payload_start = 16, |
| .payload_length = ARRAY_SIZE(bssmap_paging) - 16, |
| .first_byte = 0x0, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_cr), |
| .data = &bssmap_cr[0], |
| .payload_start = 12, |
| /* 0x00 is end of optional data, subtract this byte */ |
| .payload_length = 31, |
| .first_byte = 0x0, |
| |
| /* the connection request should trigger a connection confirm */ |
| .write = 1, |
| .response = &bssmap_cc[0], |
| .response_length= ARRAY_SIZE(bssmap_cc), |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_dtap), |
| .data = &bssmap_dtap[0], |
| .payload_start = 7, |
| .payload_length = 15, |
| .first_byte = 0x01, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_clear), |
| .data = &bssmap_clear[0], |
| .payload_start = 7, |
| .payload_length = 6, |
| .first_byte = 0x00, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_released), |
| .data = &bssmap_released[0], |
| .payload_length = 2, |
| .payload_start = 11, |
| .first_byte = 0x23, |
| |
| .write = 1, |
| .response = &bssmap_release_complete[0], |
| .response_length= ARRAY_SIZE(bssmap_release_complete), |
| }, |
| }; |
| |
| /* we will send UDTs and verify they look like this */ |
| static const struct test_data send_data[] = { |
| { |
| .length = ARRAY_SIZE(bssmap_udt), |
| .data = &bssmap_udt[0], |
| .payload_start = 12, |
| .payload_length = ARRAY_SIZE(bssmap_udt) - 12, |
| .first_byte = 0x0, |
| }, |
| { |
| .length = ARRAY_SIZE(bssmap_reset), |
| .data = &bssmap_reset[0], |
| .payload_start = 12, |
| .payload_length = ARRAY_SIZE(bssmap_reset) - 12, |
| .first_byte = 0x0, |
| }, |
| }; |
| |
| struct connection_test { |
| /* should the connection be refused? */ |
| int refuse; |
| |
| int with_data; |
| |
| /* on which side to close the connection? */ |
| int close_side; |
| int close_cause; |
| }; |
| |
| /* sccp connection handling we want to test */ |
| static const struct connection_test connection_tests[] = { |
| { |
| .refuse = 1, |
| }, |
| { |
| .refuse = 1, |
| .with_data = 1, |
| }, |
| { |
| .refuse = 0, |
| .close_side = 0, |
| .close_cause = 5, |
| }, |
| { |
| .refuse = 0, |
| .close_side = 0, |
| .close_cause = 5, |
| .with_data = 1, |
| }, |
| { |
| .refuse = 0, |
| .close_side = 1, |
| .close_cause = 5, |
| }, |
| { |
| .refuse = 0, |
| .close_side = 1, |
| .close_cause = 5, |
| .with_data = 1, |
| }, |
| }; |
| |
| struct sccp_parse_header_result { |
| /* results */ |
| int msg_type; |
| int wanted_len; |
| int src_ssn; |
| int dst_ssn; |
| |
| int has_src_ref, has_dst_ref; |
| struct sccp_source_reference src_ref; |
| struct sccp_source_reference dst_ref; |
| |
| /* the input */ |
| const u_int8_t *input; |
| int input_len; |
| }; |
| |
| static const u_int8_t it_test[] = { |
| 0x10, 0x01, 0x07, |
| 0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 }; |
| |
| static const u_int8_t proto_err[] = { |
| 0x0f, 0x0c, 0x04, 0x00, 0x00, |
| }; |
| |
| static const struct sccp_parse_header_result parse_result[] = { |
| { |
| .msg_type = SCCP_MSG_TYPE_IT, |
| .wanted_len = 0, |
| .src_ssn = -1, |
| .dst_ssn = -1, |
| .has_src_ref = 1, |
| .has_dst_ref = 1, |
| |
| .src_ref = { |
| .octet1 = 0x01, |
| .octet2 = 0x04, |
| .octet3 = 0x00 |
| }, |
| .dst_ref = { |
| .octet1 = 0x01, |
| .octet2 = 0x07, |
| .octet3 = 0x94, |
| }, |
| |
| .input = it_test, |
| .input_len = sizeof(it_test), |
| }, |
| { |
| .msg_type = SCCP_MSG_TYPE_ERR, |
| .wanted_len = 0, |
| .src_ssn = -1, |
| .dst_ssn = -1, |
| .has_src_ref = 0, |
| .has_dst_ref = 1, |
| .dst_ref = { |
| .octet1 = 0x0c, |
| .octet2 = 0x04, |
| .octet3 = 0x00, |
| }, |
| .input = proto_err, |
| .input_len = sizeof(proto_err), |
| }, |
| }; |
| |
| |
| /* testing procedure: |
| * - we will use sccp_write and see what will be set in the |
| * outgoing callback |
| * - we will call sccp_system_incoming and see which calls |
| * are made. And then compare it to the ones we expect. We |
| * want the payload to arrive, or callbacks to be called. |
| * - we will use sccp_connection_socket and sccp_connection_write |
| * and verify state handling of connections |
| */ |
| |
| static int current_test; |
| |
| /* |
| * test state... |
| */ |
| static int called = 0; |
| static int matched = 0; |
| static int write_called = 0; |
| |
| #define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args) |
| |
| /* |
| * writing these packets and expecting a result |
| */ |
| int sccp_read_cb(struct msgb *data, unsigned len, void *context) |
| { |
| u_int16_t payload_length = test_data[current_test].payload_length; |
| const u_int8_t *got, *wanted; |
| int i; |
| |
| called = 1; |
| |
| if (msgb_l3len(data) < len) { |
| /* this should never be reached */ |
| FAIL("Something horrible happened.. invalid packet..\n"); |
| exit(-1); |
| } |
| |
| if (len == 0 || len != payload_length) { |
| FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length); |
| return -1; |
| } |
| |
| if (data->l3h[0] != test_data[current_test].first_byte) { |
| FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n", |
| data->l3h[0], test_data[current_test].first_byte); |
| return -1; |
| } |
| |
| got = &data->l3h[0]; |
| wanted = test_data[current_test].data + test_data[current_test].payload_start; |
| |
| for (i = 0; i < len; ++i) { |
| if (got[i] != wanted[i]) { |
| FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", |
| got[i], wanted[i], i); |
| return -1; |
| } |
| } |
| |
| matched = 1; |
| return 0; |
| } |
| |
| void sccp_write_cb(struct msgb *data, void *ctx) |
| { |
| int i = 0; |
| const u_int8_t *got, *wanted; |
| |
| if (test_data[current_test].response == NULL) { |
| FAIL("Didn't expect write callback\n"); |
| goto exit; |
| } else if (test_data[current_test].response_length != msgb_l2len(data)) { |
| FAIL("Size does not match. Got: %d Wanted: %d\n", |
| msgb_l2len(data), test_data[current_test].response_length); |
| } |
| |
| got = &data->l2h[0]; |
| wanted = test_data[current_test].response; |
| |
| for (i = 0; i < msgb_l2len(data); ++i) { |
| if (got[i] != wanted[i]) { |
| FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", |
| got[i], wanted[i], i); |
| goto exit; |
| } |
| } |
| |
| write_called = 1; |
| |
| exit: |
| msgb_free(data); |
| } |
| |
| void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len) |
| { |
| sccp_read_cb(msgb, len, connection->data_ctx); |
| } |
| |
| void sccp_c_state(struct sccp_connection *connection, int old_state) |
| { |
| if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) |
| sccp_connection_free(connection); |
| } |
| |
| int sccp_accept_cb(struct sccp_connection *connection, void *user_data) |
| { |
| called = 1; |
| unsigned int ref = 0; |
| ref |= connection->destination_local_reference.octet1 << 24; |
| ref |= connection->destination_local_reference.octet2 << 16; |
| ref |= connection->destination_local_reference.octet3 << 8; |
| ref = ntohl(ref); |
| |
| connection->data_cb = sccp_c_read; |
| connection->state_cb = sccp_c_state; |
| |
| /* accept this */ |
| return 0; |
| } |
| |
| static void sccp_udt_write_cb(struct msgb *data, void *context) |
| { |
| const u_int8_t *got, *wanted; |
| int i; |
| |
| write_called = 1; |
| |
| if (send_data[current_test].length != msgb_l2len(data)) { |
| FAIL("Size does not match. Got: %d Wanted: %d\n", |
| msgb_l2len(data), send_data[current_test].length); |
| goto exit; |
| } |
| |
| got = &data->l2h[0]; |
| wanted = send_data[current_test].data; |
| |
| for (i = 0; i < msgb_l2len(data); ++i) { |
| if (got[i] != wanted[i]) { |
| FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", |
| got[i], wanted[i], i); |
| goto exit; |
| } |
| } |
| |
| matched = 1; |
| |
| exit: |
| msgb_free(data); |
| } |
| |
| static void test_sccp_system(void) |
| { |
| sccp_system_init(sccp_write_cb, NULL); |
| sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); |
| sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); |
| |
| for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { |
| unsigned int length = test_data[current_test].length; |
| struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); |
| msg->l2h = msgb_put(msg, length); |
| memcpy(msg->l2h, test_data[current_test].data, length); |
| |
| called = matched = write_called = 0; |
| printf("Testing packet: %d\n", current_test); |
| sccp_system_incoming(msg); |
| |
| if (!called || !matched || (test_data[current_test].write != write_called)) |
| FAIL("current test: %d called: %d matched: %d write: %d\n", |
| current_test, called, matched, write_called); |
| |
| msgb_free(msg); |
| } |
| } |
| |
| /* test sending of udt */ |
| static void test_sccp_send_udt(void) |
| { |
| sccp_system_init(sccp_udt_write_cb, NULL); |
| sccp_set_read(NULL, NULL, NULL); |
| sccp_connection_set_incoming(NULL, NULL, NULL); |
| |
| for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) { |
| const struct test_data *test = &send_data[current_test]; |
| |
| struct msgb *msg = msgb_alloc(test->payload_length, __func__); |
| msg->l3h = msgb_put(msg, test->payload_length); |
| memcpy(msg->l3h, test->data + test->payload_start, test->payload_length); |
| |
| matched = write_called = 0; |
| printf("Testing packet: %d\n", current_test); |
| sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); |
| |
| if (!matched || !write_called) |
| FAIL("current test: %d matched: %d write: %d\n", |
| current_test, matched, write_called); |
| |
| msgb_free(msg); |
| } |
| } |
| |
| /* send udt from one end to another */ |
| static unsigned int test_value = 0x2442; |
| static int sccp_udt_read(struct msgb *data, unsigned int len, void *context) |
| { |
| unsigned int *val; |
| |
| if (len != 4) { |
| FAIL("Wrong size: %d\n", msgb_l3len(data)); |
| return -1; |
| } |
| |
| val = (unsigned int*)data->l3h; |
| matched = test_value == *val; |
| |
| return 0; |
| } |
| |
| static void sccp_write_loop(struct msgb *data, void *context) |
| { |
| /* send it back to us */ |
| sccp_system_incoming(data); |
| msgb_free(data); |
| } |
| |
| static void test_sccp_udt_communication(void) |
| { |
| struct msgb *data; |
| unsigned int *val; |
| |
| sccp_system_init(sccp_write_loop, NULL); |
| sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL); |
| sccp_connection_set_incoming(NULL, NULL, NULL); |
| |
| |
| data = msgb_alloc(4, "test data"); |
| data->l3h = &data->data[0]; |
| val = (unsigned int *)msgb_put(data, 4); |
| *val = test_value; |
| |
| matched = 0; |
| sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); |
| |
| if (!matched) |
| FAIL("Talking with us didn't work\n"); |
| |
| msgb_free(data); |
| } |
| |
| |
| /* connection testing... open, send, close */ |
| static const struct connection_test *current_con_test; |
| static struct sccp_connection *outgoing_con; |
| static struct sccp_connection *incoming_con; |
| static int outgoing_data, incoming_data, incoming_state, outgoing_state; |
| |
| static struct msgb *test_data1, *test_data2, *test_data3; |
| |
| static void sccp_conn_in_state(struct sccp_connection *conn, int old_state) |
| { |
| printf("\tincome: %d -> %d\n", old_state, conn->connection_state); |
| if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { |
| if (conn == incoming_con) { |
| sccp_connection_free(conn); |
| incoming_con = NULL; |
| } |
| } |
| } |
| |
| static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) |
| { |
| /* compare the data */ |
| ++incoming_data; |
| printf("\tincoming data: %d\n", len); |
| |
| /* compare the data */ |
| if (len != 4) { |
| FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); |
| return; |
| } |
| |
| if (incoming_data == 1) { |
| if (memcmp(msg->l3h, test_data1->l3h, len) != 0) { |
| FAIL("Comparing the data failed: %d\n", incoming_data); |
| incoming_state = 0; |
| printf("Got: %s\n", hexdump(msg->l3h, len)); |
| printf("Wanted: %s\n", hexdump(test_data1->l3h, len)); |
| |
| } |
| } else if (incoming_data == 2) { |
| if (memcmp(msg->l3h, test_data2->l3h, len) != 0) { |
| FAIL("Comparing the data failed: %d\n", incoming_data); |
| incoming_state = 0; |
| printf("Got: %s\n", hexdump(msg->l3h, len)); |
| printf("Wanted: %s\n", hexdump(test_data2->l3h, len)); |
| } |
| } |
| |
| /* sending out data */ |
| if (incoming_data == 2) { |
| printf("\tReturning data3\n"); |
| sccp_connection_write(conn, test_data3); |
| } |
| } |
| |
| static int sccp_conn_accept(struct sccp_connection *conn, void *ctx) |
| { |
| printf("\taccept: %p\n", conn); |
| conn->state_cb = sccp_conn_in_state; |
| conn->data_cb = sccp_conn_in_data; |
| |
| if (current_con_test->refuse) |
| return -1; |
| |
| incoming_con = conn; |
| return 0; |
| } |
| |
| /* callbacks for the outgoing side */ |
| static void sccp_conn_out_state(struct sccp_connection *conn, int old_state) |
| { |
| printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state); |
| |
| if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { |
| if (conn == outgoing_con) { |
| sccp_connection_free(conn); |
| outgoing_con = NULL; |
| } |
| } |
| } |
| |
| static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) |
| { |
| ++outgoing_data; |
| printf("\toutgoing data: %p %d\n", conn, len); |
| |
| if (len != 4) |
| FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); |
| |
| if (outgoing_data == 1) { |
| if (memcmp(msg->l3h, test_data3->l3h, len) != 0) { |
| FAIL("Comparing the data failed\n"); |
| outgoing_state = 0; |
| } |
| } |
| } |
| |
| static void do_test_sccp_connection(const struct connection_test *test) |
| { |
| int ret; |
| |
| current_con_test = test; |
| outgoing_con = incoming_con = 0; |
| |
| outgoing_con = sccp_connection_socket(); |
| if (!outgoing_con) { |
| FAIL("Connection is NULL\n"); |
| return; |
| } |
| |
| outgoing_con->state_cb = sccp_conn_out_state; |
| outgoing_con->data_cb = sccp_conn_out_data; |
| outgoing_data = incoming_data = 0; |
| incoming_state = outgoing_state = 1; |
| |
| /* start testing */ |
| if (test->with_data) { |
| if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0) |
| FAIL("Binding failed\n"); |
| } else { |
| ++incoming_data; |
| if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0) |
| FAIL("Binding failed\n"); |
| } |
| |
| if (test->refuse) { |
| if (outgoing_con) |
| FAIL("Outgoing connection should have been refused.\n"); |
| } else { |
| if (!incoming_con) |
| FAIL("Creating incoming didn't work.\n"); |
| |
| printf("\tWriting test data2\n"); |
| sccp_connection_write(outgoing_con, test_data2); |
| sccp_connection_send_it(outgoing_con); |
| |
| /* closing connection */ |
| if (test->close_side == 0) |
| ret = sccp_connection_close(outgoing_con, 0); |
| else |
| ret = sccp_connection_close(incoming_con, 0); |
| |
| if (ret != 0) |
| FAIL("Closing the connection failed\n"); |
| } |
| |
| /* outgoing should be gone now */ |
| if (outgoing_con) |
| FAIL("Outgoing connection was not properly closed\n"); |
| |
| if (incoming_con) |
| FAIL("Incoming connection was not propery closed.\n"); |
| |
| if (test->refuse == 0) { |
| if (outgoing_data != 1 || incoming_data != 2) { |
| FAIL("Data sending failed: %d/%d %d/%d\n", |
| outgoing_data, 1, |
| incoming_data, 2); |
| } |
| } |
| |
| if (!incoming_state || !outgoing_state) |
| FAIL("Failure with the state transition. %d %d\n", |
| outgoing_state, incoming_state); |
| } |
| |
| static void test_sccp_connection(void) |
| { |
| sccp_system_init(sccp_write_loop, NULL); |
| sccp_set_read(NULL, NULL, NULL); |
| sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL); |
| |
| test_data1 = msgb_alloc(4, "data1"); |
| test_data1->l3h = msgb_put(test_data1, 4); |
| *((unsigned int*)test_data1->l3h) = 0x23421122; |
| |
| test_data2 = msgb_alloc(4, "data2"); |
| test_data2->l3h = msgb_put(test_data2, 4); |
| *((unsigned int*)test_data2->l3h) = 0x42232211; |
| |
| test_data3 = msgb_alloc(4, "data3"); |
| test_data3->l3h = msgb_put(test_data3, 4); |
| *((unsigned int*)test_data3->l3h) = 0x2323ff55; |
| |
| |
| for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) { |
| printf("Testing %d refuse: %d with_data: %d\n", |
| current_test, connection_tests[current_test].refuse, |
| connection_tests[current_test].with_data); |
| do_test_sccp_connection(&connection_tests[current_test]); |
| } |
| |
| msgb_free(test_data1); |
| msgb_free(test_data2); |
| msgb_free(test_data3); |
| } |
| |
| /* invalid input */ |
| static void test_sccp_system_crash(void) |
| { |
| printf("trying to provoke a crash with invalid input\n"); |
| sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); |
| sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); |
| |
| for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { |
| int original_length = test_data[current_test].length; |
| int length = original_length + 2; |
| int i; |
| |
| printf("Testing packet: %d\n", current_test); |
| |
| for (i = length; i >= 0; --i) { |
| unsigned int length = MIN(test_data[current_test].length, i); |
| struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); |
| msg->l2h = msgb_put(msg, length); |
| memcpy(msg->l2h, test_data[current_test].data, length); |
| sccp_system_incoming(msg); |
| msgb_free(msg); |
| } |
| } |
| |
| printf("survived\n"); |
| } |
| |
| static void test_sccp_parsing(void) |
| { |
| for (current_test = 0; current_test < ARRAY_SIZE(parse_result); ++current_test) { |
| struct msgb *msg; |
| struct sccp_parse_result result; |
| |
| msg = msgb_alloc_headroom(1024, 128, "parse-test"); |
| msgb_put(msg, 1); |
| msg->l2h = msgb_put(msg, parse_result[current_test].input_len); |
| memcpy(msg->l2h, parse_result[current_test].input, msgb_l2len(msg)); |
| |
| memset(&result, 0, sizeof(result)); |
| if (sccp_parse_header(msg, &result) != 0) { |
| fprintf(stderr, "Failed to sccp parse test: %d\n", current_test); |
| } else { |
| if (parse_result[current_test].wanted_len != result.data_len) { |
| fprintf(stderr, "Unexpected data length.\n"); |
| abort(); |
| } |
| |
| if (parse_result[current_test].has_src_ref) { |
| if (memcmp(result.source_local_reference, |
| &parse_result[current_test].src_ref, |
| sizeof(struct sccp_source_reference)) != 0) { |
| fprintf(stderr, "SRC REF did not match\n"); |
| abort(); |
| } |
| } |
| |
| if (parse_result[current_test].has_dst_ref) { |
| if (memcmp(result.destination_local_reference, |
| &parse_result[current_test].dst_ref, |
| sizeof(struct sccp_source_reference)) != 0) { |
| fprintf(stderr, "DST REF did not match\n"); |
| abort(); |
| } |
| } |
| |
| if (parse_result[current_test].src_ssn != -1) { |
| fprintf(stderr, "Not implemented.\n"); |
| abort(); |
| } |
| |
| if (parse_result[current_test].dst_ssn != -1) { |
| fprintf(stderr, "Not implemented.\n"); |
| abort(); |
| } |
| } |
| |
| msgb_free(msg); |
| } |
| } |
| |
| |
| int main(int argc, char **argv) |
| { |
| test_sccp_system(); |
| test_sccp_send_udt(); |
| test_sccp_udt_communication(); |
| test_sccp_connection(); |
| test_sccp_system_crash(); |
| test_sccp_parsing(); |
| return 0; |
| } |
| |
| void db_store_counter() {} |