libosmo-sccp/tests/xua/xua_test.c

387 lines
10 KiB
C
Raw Normal View History

/* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "sccp_test_data.h"
#include "../src/xua_internal.h"
#include <osmocom/sigtran/xua_msg.h>
#include <osmocom/sigtran/protocol/sua.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
static void test_isup_parse(void)
{
const uint8_t party0[] = { 0x10, 0x32, 0x54, 0x76 };
char digits[23] = "";
int rc;
rc = osmo_isup_party_parse(digits, party0, ARRAY_SIZE(party0), false);
printf("digits='%s' (%d)\n", digits, rc);
OSMO_ASSERT(rc == 8);
OSMO_ASSERT(!strcmp(digits, "01234567"));
rc = osmo_isup_party_parse(digits, party0, ARRAY_SIZE(party0), true);
printf("digits='%s' (%d)\n", digits, rc);
OSMO_ASSERT(rc == 7);
OSMO_ASSERT(!strcmp(digits, "0123456"));
}
/* SCCP Address Parsing */
static struct sccp_addr_testcase {
struct osmo_sccp_addr expected;
uint8_t *bin;
unsigned int bin_len;
};
static uint8_t addr_bin0[] = { 0x92, 0x06, 0x00, 0x12, 0x04, 0x19, 0x99, 0x96, 0x76, 0x39, 0x98 };
static uint8_t addr_bin1[] = { 0x12, 0x08, 0x00, 0x12, 0x04, 0x19, 0x89, 0x96, 0x92, 0x99, 0x29 };
static uint8_t addr_bin2[] = { 0x42, 0xfe };
static const struct sccp_addr_testcase sccp_addr_testcases[] = {
{
.expected = {
.presence = OSMO_SCCP_ADDR_T_GT | OSMO_SCCP_ADDR_T_SSN,
.ri = OSMO_SCCP_RI_GT,
.gt = {
.gti = OSMO_SCCP_GTI_TT_NPL_ENC_NAI,
.tt = 0,
.npi = OSMO_SCCP_NPI_E164_ISDN,
.nai = OSMO_SCCP_NAI_INTL,
.digits = "919969679389",
},
.ssn = 6,
},
.bin = addr_bin0,
.bin_len = ARRAY_SIZE(addr_bin0),
}, {
.expected = {
.presence = OSMO_SCCP_ADDR_T_GT | OSMO_SCCP_ADDR_T_SSN,
.ri = OSMO_SCCP_RI_GT,
.gt = {
.gti = OSMO_SCCP_GTI_TT_NPL_ENC_NAI,
.tt = 0,
.npi = OSMO_SCCP_NPI_E164_ISDN,
.nai = OSMO_SCCP_NAI_INTL,
.digits = "919869299992",
},
.ssn = 8,
},
.bin = addr_bin1,
.bin_len = ARRAY_SIZE(addr_bin1),
}, {
.expected = {
.presence = OSMO_SCCP_ADDR_T_SSN,
.ri = OSMO_SCCP_RI_SSN_PC,
.ssn = 254,
},
.bin = addr_bin2,
.bin_len = ARRAY_SIZE(addr_bin2),
},
};
static int test_sccp_addr_parse(const struct osmo_sccp_addr *cmp,
const uint8_t *in, unsigned int in_len)
{
struct osmo_sccp_addr osa;
int rc;
memset(&osa, 0, sizeof(osa));
rc = osmo_sccp_addr_parse(&osa, in, in_len);
if (rc < 0)
return rc;
printf("expected: %s\n", osmo_sccp_addr_dump(cmp));
printf("parsed: %s\n", osmo_sccp_addr_dump(&osa));
if (memcmp(&osa, cmp, sizeof(osa))) {
fprintf(stderr, "expected: %s\n", osmo_hexdump_nospc((uint8_t *)cmp, sizeof(*cmp)));
fprintf(stderr, "parsed: %s\n", osmo_hexdump_nospc((uint8_t *)&osa, sizeof(osa)));
}
return 0;
}
static void test_sccp_addr_parser(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(sccp_addr_testcases); i++) {
const struct sccp_addr_testcase *tcase = &sccp_addr_testcases[i];
printf("sccp_addr_parse test case %u\n", i);
test_sccp_addr_parse(&tcase->expected, tcase->bin, tcase->bin_len);
}
}
/* sccp_addr_testcases[0].expected.gt transcoded into a SUA Global Title IE */
static const uint8_t expected_sua_gt[] = {
0x80, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04,
0x0c, 0x00, 0x01, 0x04, 0x19, 0x99, 0x96, 0x76,
0x39, 0x98, 0x00, 0x00
};
static void test_helpers(void)
{
struct msgb *msg = msgb_alloc(1024, "foo");
const struct osmo_sccp_gt *gt_in = &sccp_addr_testcases[0].expected.gt;
struct osmo_sccp_gt gt_out;
printf("Testing Decoded GT -> SUA encoding\n");
printf("IN: %s\n", osmo_sccp_gt_dump(gt_in));
/* encode sccp_addr to SUA GT */
xua_part_add_gt(msg, gt_in);
OSMO_ASSERT(msgb_length(msg) == sizeof(expected_sua_gt));
OSMO_ASSERT(!memcmp(msg->data, expected_sua_gt, sizeof(expected_sua_gt)));
/* pull the tag+length value */
msgb_pull(msg, 4);
/* parse + compare */
sua_parse_gt(&gt_out, msgb_data(msg), msgb_length(msg));
printf("OUT:%s\n", osmo_sccp_gt_dump(&gt_out));
OSMO_ASSERT(!memcmp(gt_in, &gt_out, sizeof(gt_out)));
msgb_free(msg);
}
/* SCCP Message Transcoding */
struct sccp2sua_testcase {
const char *name;
struct {
const uint8_t *bin;
unsigned int length;
} sccp;
struct {
struct xua_common_hdr hdr;
const struct xua_msg_part parts[32];
} sua;
};
#define PANDSIZ(x) { x, ARRAY_SIZE(x) }
#define PARTU32(x, data) { .tag = x, .len = 4, .dat = (uint8_t *) data }
#define PARTARR(x, data) { .tag = x, .len = ARRAY_SIZE(data), .dat = (uint8_t *) data }
const uint32_t sua_proto_class0 = 0;
const uint32_t sua_proto_class2 = 2;
const uint32_t sua_loc_ref_bsc = 0x10203;
const uint32_t sua_loc_ref_msc = 0x00003;
const uint32_t sua_cause0 = 0x00003;
const uint8_t sua_addr_ssn_bssmap[] = { 0x00, 0x02, 0x00, 0x07, 0x80, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfe };
const uint8_t sua_addr_ssn_bssmap_pc1[] = { 0x00, 0x01, 0x00, 0x07, 0x80, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfe };
const uint8_t sua_addr_ssn_bssmap_pc92[] = { 0x00, 0x01, 0x00, 0x07, 0x80, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5c, 0x80, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfe };
static const struct sccp2sua_testcase sccp2sua_testcases[] = {
{
.name = "BSSMAP-RESET",
.sccp = PANDSIZ(bssmap_reset),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CL, SUA_CL_CLDT),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class0),
PARTARR(SUA_IEI_DEST_ADDR, &sua_addr_ssn_bssmap),
PARTARR(SUA_IEI_SRC_ADDR, &sua_addr_ssn_bssmap),
},
},
}, {
.name = "BSSMAP-RESET-ACK",
.sccp = PANDSIZ(bssmap_reset_ack),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CL, SUA_CL_CLDT),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class0),
PARTARR(SUA_IEI_DEST_ADDR, &sua_addr_ssn_bssmap_pc1),
PARTARR(SUA_IEI_SRC_ADDR, &sua_addr_ssn_bssmap_pc92),
},
},
}, {
.name = "BSSMAP-PAGING",
.sccp = PANDSIZ(bssmap_paging),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CL, SUA_CL_CLDT),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class0),
PARTARR(SUA_IEI_DEST_ADDR, &sua_addr_ssn_bssmap_pc1),
PARTARR(SUA_IEI_SRC_ADDR, &sua_addr_ssn_bssmap_pc92),
},
},
}, {
.name = "BSSMAP-UDT",
.sccp = PANDSIZ(bssmap_udt),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CL, SUA_CL_CLDT),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class0),
PARTARR(SUA_IEI_DEST_ADDR, &sua_addr_ssn_bssmap),
PARTARR(SUA_IEI_SRC_ADDR, &sua_addr_ssn_bssmap),
},
},
}, {
.name = "BSSMAP-CR",
.sccp = PANDSIZ(bssmap_cr),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_CORE),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class2),
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_bsc),
PARTARR(SUA_IEI_DEST_ADDR, &sua_addr_ssn_bssmap),
},
},
}, {
.name = "BSSMAP-CC",
.sccp = PANDSIZ(bssmap_cc),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_COAK),
.parts = {
PARTU32(SUA_IEI_PROTO_CLASS, &sua_proto_class2),
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_msc),
PARTARR(SUA_IEI_DEST_ADDR, &sua_loc_ref_bsc),
},
},
}, {
.name = "BSSMAP-DTAP",
.sccp = PANDSIZ(bssmap_dtap),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_CODT),
.parts = {
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_msc),
},
},
}, {
.name = "BSSMAP-CLEAR",
.sccp = PANDSIZ(bssmap_clear),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_CODT),
.parts = {
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_msc),
},
},
}, {
.name = "BSSMAP-RELEASED",
.sccp = PANDSIZ(bssmap_released),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_RELRE),
.parts = {
PARTU32(SUA_IEI_DEST_REF, &sua_loc_ref_msc),
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_bsc),
PARTU32(SUA_IEI_CAUSE, &sua_cause0),
},
},
}, {
.name = "BSSMAP-RELEASE_COMPLETE",
.sccp = PANDSIZ(bssmap_release_complete),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CO, SUA_CO_RELCO),
.parts = {
PARTU32(SUA_IEI_DEST_REF, &sua_loc_ref_bsc),
PARTU32(SUA_IEI_SRC_REF, &sua_loc_ref_msc),
},
},
}, {
.name = "TCAP",
.sccp = PANDSIZ(tcap_global_title),
.sua = {
.hdr = XUA_HDR(SUA_MSGC_CL, SUA_CL_CLDT),
.parts = {
},
},
},
};
static void test_sccp2sua_case(const struct sccp2sua_testcase *tcase)
{
struct xua_msg *xua;
struct msgb *msg = msgb_alloc(300, "SCCP2SUA Test Input");
struct msgb *msg2;
printf("\n=> %s\n", tcase->name);
msg->l2h = msgb_put(msg, tcase->sccp.length);
memcpy(msg->l2h, tcase->sccp.bin, tcase->sccp.length);
printf("SCCP Input: %s\n", msgb_hexdump(msg));
printf("Transcoding message SCCP -> XUA\n");
xua = osmo_sccp_to_xua(msg);
OSMO_ASSERT(xua);
printf("Decoded SUA: ");
printf("%s\n", xua_msg_dump(xua, &xua_dialect_sua));
printf("Re-Encoding decoded SUA to SCCP\n");
msg2 = osmo_sua_to_sccp(xua);
OSMO_ASSERT(msg2);
/* Re-encode xUA to SCCP */
printf("SCCP Output: %s\n", msgb_hexdump(msg2));
if (msgb_length(msg) != msgb_length(msg2) ||
memcmp(msgb_data(msg), msgb_data(msg2), msgb_length(msg)))
printf("Input != re-encoded output!\n");
/* free related data */
msgb_free(msg);
msgb_free(msg2);
xua_msg_free(xua);
}
static void test_sccp2sua(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(sccp2sua_testcases); i++) {
test_sccp2sua_case(&sccp2sua_testcases[i]);
}
}
static const struct log_info_cat default_categories[] = {
[0] = {
.name = "DSCCP",
.description = "DSCP",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
static const struct log_info log_info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
int main(int argc, char **argv)
{
struct log_target *stderr_target;
log_init(&log_info, NULL);
stderr_target = log_target_create_stderr();
log_add_target(stderr_target);
test_isup_parse();
test_sccp_addr_parser();
test_helpers();
test_sccp2sua();
printf("All tests passed.\n");
return 0;
}