/* * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH * All Rights Reserved. * * Author: Neels Janosch Hofmeyr * * SPDX-License-Identifier: GPL-2.0+ * * 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, see . * */ #include #include #include #include #include #include void *ctx; /* struct osmo_sockaddr */ #define v4_ue { \ .u.sin = { \ .sin_family = AF_INET, \ .sin_addr = { 0x1700a8c0 }, \ } \ } /* struct osmo_sockaddr */ #define v4_gtp { \ .u.sin = { \ .sin_family = AF_INET, \ .sin_addr = { 0x0708090a }, \ } \ } /* struct osmo_pfcp_ie_f_teid */ #define f_teid_access_local { \ .choose_flag = true, \ .choose = { \ .ipv4_addr = true, \ }, \ } /* struct osmo_pfcp_ie_f_teid */ #define f_teid_created { \ .fixed = { \ .teid = 1234, \ .ip_addr = { \ .v4_present = true, \ .v4 = v4_gtp, \ }, \ }, \ } /* struct osmo_pfcp_ie_outer_header_creation */ #define ohc_access { \ .desc_bits = { 0x01 }, \ .teid_present = true, \ .teid = 0xabcdef, \ .ip_addr = { \ .v4_present = true, \ .v4 = v4_gtp, \ }, \ } /* struct osmo_pfcp_ie_apply_action */ #define aa_forw { \ .bits = { 0x02 }, \ } /* struct osmo_pfcp_ie_f_seid */ #define f_seid { \ .seid = 0x1234567890abcdef, \ .ip_addr = { \ .v4_present = true, \ .v4 = v4_gtp, \ }, \ } struct osmo_pfcp_msg tests[] = { { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_HEARTBEAT_REQ, .sequence_nr = 1, }, .ies.heartbeat_req = { .recovery_time_stamp = 1234, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_HEARTBEAT_RESP, .sequence_nr = 2, }, .ies.heartbeat_resp = { .recovery_time_stamp = 5678, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_ASSOC_SETUP_REQ, .sequence_nr = 3, }, .ies.assoc_setup_req = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_IPV4, .ip.u.sin = { .sin_family = AF_INET, .sin_addr = { 0x01020304 }, }, }, .recovery_time_stamp = 0x2b2b2b2b, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_ASSOC_SETUP_RESP, .sequence_nr = 4, }, .ies.assoc_setup_resp = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_FQDN, .fqdn = "example.com", }, .cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED, .recovery_time_stamp = 0x2b2b2b2b, .up_function_features_present = true, .up_function_features.bits = { 1, 2 }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_ASSOC_RELEASE_REQ, .sequence_nr = 5, }, .ies.assoc_release_req = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_IPV6, .ip.u.sin6 = { .sin6_family = AF_INET6, .sin6_addr = {{{ 1, 2, 3, 4 }}}, }, }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP, .sequence_nr = 6, }, .ies.assoc_release_resp = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_IPV4, .ip.u.sin = { .sin_family = AF_INET, .sin_addr = { 0x01020304 }, }, }, .cause = OSMO_PFCP_CAUSE_REQUEST_REJECTED, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_EST_REQ, .sequence_nr = 7, .seid_present = true, .seid = 0, }, .ies.session_est_req = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_IPV4, .ip.u.sin = { .sin_family = AF_INET, .sin_addr = { 0x0100007f }, }, }, .cp_f_seid_present = true, .cp_f_seid = f_seid, .create_pdr_count = 2, .create_pdr = { { .pdr_id = 1, .precedence = 255, .pdi = { .source_iface = OSMO_PFCP_SOURCE_IFACE_CORE, .network_inst_present = true, .network_inst = { .str = "foo", }, .ue_ip_address_present = true, .ue_ip_address = { .ip_is_destination = true, .ip_addr = { .v4_present = true, .v4 = v4_ue, }, }, }, .far_id_present = true, .far_id = 1, }, { .pdr_id = 2, .precedence = 255, .pdi = { .source_iface = OSMO_PFCP_SOURCE_IFACE_ACCESS, .local_f_teid_present = true, .local_f_teid = f_teid_access_local, .network_inst_present = true, .network_inst = { .str = "bar", }, }, .outer_header_removal_present = true, .outer_header_removal = { .desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4, }, .far_id_present = true, .far_id = 2, }, }, .create_far_count = 2, .create_far = { { .far_id = 1, .forw_params_present = true, .forw_params = { .destination_iface = OSMO_PFCP_DEST_IFACE_ACCESS, .outer_header_creation_present = true, .outer_header_creation = ohc_access, }, .apply_action = aa_forw, }, { .far_id = 2, .forw_params_present = true, .forw_params = { .destination_iface = OSMO_PFCP_DEST_IFACE_CORE, }, .apply_action = aa_forw, }, }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_EST_RESP, .sequence_nr = 8, .seid_present = true, .seid = 0x0123456789abcdef, }, .ies.session_est_resp = { .node_id = { .type = OSMO_PFCP_NODE_ID_T_IPV4, .ip.u.sin = { .sin_family = AF_INET, .sin_addr = { 0x0200007f }, }, }, .cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED, .up_f_seid_present = true, .up_f_seid = f_seid, .created_pdr_count = 2, .created_pdr = { { .pdr_id = 1, }, { .pdr_id = 2, .local_f_teid_present = true, .local_f_teid = f_teid_created, }, }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_MOD_REQ, .sequence_nr = 9, .seid_present = true, .seid = 0, }, .ies.session_mod_req = { .remove_pdr_count = 1, .remove_pdr = { { .pdr_id = 1, }, }, .remove_far_count = 1, .remove_far = { { .far_id = 1, }, }, .create_pdr_count = 1, .create_pdr = { { .pdr_id = 3, .precedence = 255, .pdi = { .source_iface = OSMO_PFCP_SOURCE_IFACE_ACCESS, .local_f_teid_present = true, .local_f_teid = f_teid_access_local, .network_inst_present = true, .network_inst = { .str = "baz", }, }, .outer_header_removal_present = true, .outer_header_removal = { .desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4, }, .far_id_present = true, .far_id = 3, }, }, .create_far_count = 1, .create_far = { { .far_id = 3, .forw_params_present = true, .forw_params = { .destination_iface = OSMO_PFCP_DEST_IFACE_ACCESS, .outer_header_creation_present = true, .outer_header_creation = ohc_access, }, .apply_action = aa_forw, }, }, .upd_pdr_count = 1, .upd_pdr = { { .pdr_id = 1, .pdi_present = true, .pdi = { .source_iface = OSMO_PFCP_SOURCE_IFACE_ACCESS, .local_f_teid_present = true, .local_f_teid = f_teid_access_local, .network_inst_present = true, .network_inst = { .str = "moo", }, }, .outer_header_removal_present = true, .outer_header_removal = { .desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4, }, .far_id_present = true, .far_id = 1, }, }, .upd_far_count = 1, .upd_far = { { .far_id = 1, .upd_forw_params_present = true, .upd_forw_params = { .destination_iface = OSMO_PFCP_DEST_IFACE_CORE, .network_inst_present = true, .network_inst = { .str = "internet", }, }, .apply_action = aa_forw, }, }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_MOD_RESP, .sequence_nr = 10, .seid_present = true, .seid = 0x0123456789abcdef, }, .ies.session_mod_resp = { .cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED, .created_pdr_count = 1, .created_pdr = { { .pdr_id = 3, .local_f_teid_present = true, .local_f_teid = f_teid_created, }, }, .updated_pdr_count = 1, .updated_pdr = { { .pdr_id = 1, .local_f_teid_present = true, .local_f_teid = f_teid_created, }, }, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_MOD_RESP, .sequence_nr = 11, .seid_present = true, .seid = 0x0123456789abcdef, }, .ies.session_mod_resp = { .cause = OSMO_PFCP_CAUSE_MANDATORY_IE_MISSING, .offending_ie_present = true, .offending_ie = OSMO_PFCP_IEI_APPLY_ACTION, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_DEL_REQ, .sequence_nr = 12, .seid_present = true, .seid = 0x0123456789abcdef, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_DEL_RESP, .sequence_nr = 13, .seid_present = true, .seid = 0x0123456789abcdef, }, .ies.session_del_resp = { .cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC, }, }, { .h = { .version = 1, .message_type = OSMO_PFCP_MSGT_SESSION_DEL_RESP, .sequence_nr = 13, .seid_present = true, .seid = 0x0123456789abcdef, }, .ies.session_del_resp = { .cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED, }, }, }; void test_enc_dec(void) { int i; for (i = 0; i < ARRAY_SIZE(tests); i++) { void *loop_ctx = talloc_named_const(ctx, 0, "loop"); int rc; const struct osmo_pfcp_msg *orig = &tests[i]; struct osmo_pfcp_msg parsed = {}; struct msgb *msg; struct osmo_gtlv_load tlv; printf("\n=== start %s[%d]\n", __func__, i); printf("encoding: %s\n", osmo_pfcp_message_type_str(orig->h.message_type)); printf("%s\n", osmo_pfcp_msg_to_str_c(loop_ctx, orig)); msg = msgb_alloc(1024, __func__); rc = osmo_pfcp_msg_encode(msg, orig); printf("osmo_pfcp_msg_encode() rc = %d\n", rc); printf("%s.\n", osmo_hexdump(msg->data, msg->len)); rc = osmo_pfcp_msg_decode_header(&tlv, &parsed, msg); printf("osmo_pfcp_msg_decode_header() rc = %d\n", rc); if (rc != msgb_length(msg)) { printf("ERROR: expected rc = %d\n", msgb_length(msg)); exit(1); } else { printf("rc == msgb_length()\n"); } rc = osmo_pfcp_msg_decode_tlv(&parsed, &tlv); printf("osmo_pfcp_msg_decode_tlv() rc = %d\n", rc); if (strcmp(osmo_pfcp_msg_to_str_c(loop_ctx, orig), osmo_pfcp_msg_to_str_c(loop_ctx, &parsed))) { printf(" ERROR: parsed != orig\n"); printf(" orig: %s\n", osmo_pfcp_msg_to_str_c(loop_ctx, orig)); printf(" parsed: %s\n", osmo_pfcp_msg_to_str_c(loop_ctx, &parsed)); exit(1); } else { printf("parsed == orig\n"); } msgb_free(msg); printf("=== end %s[%d]\n", __func__, i); talloc_free(loop_ctx); } } static const struct log_info_cat log_categories[] = { }; const struct log_info log_info = { .cat = log_categories, .num_cat = ARRAY_SIZE(log_categories), }; int main(int argc, char **argv) { ctx = talloc_named_const(NULL, 0, "pfcp_test"); msgb_talloc_ctx_init(ctx, 0); /* If libosmo-pfcp encounters encoding/decoding errors, it causes logging in DLPFCP. */ osmo_init_logging2(ctx, &log_info); log_set_print_category_hex(osmo_stderr_target, 0); log_set_print_category(osmo_stderr_target, 1); log_set_print_level(osmo_stderr_target, 1); log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); log_set_print_timestamp(osmo_stderr_target, 0); log_set_print_extended_timestamp(osmo_stderr_target, 0); test_enc_dec(); log_fini(); talloc_free(ctx); return 0; }