diff --git a/.travis.yml b/.travis.yml index b1ea0ae..f41cae2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,13 @@ -dist: xenial +sudo: required +dist: bionic language: erlang otp_release: - - 20.1.7 - - 20.3.8.5 - - 21.0 - - 21.1.4 - - 21.2.7 - 21.3.8.1 - 22.0.7 - 22.1.8 + - 22.2.4 install: "true" @@ -24,3 +21,6 @@ script: - ./rebar3 compile - ./rebar3 do xref, ct - (./rebar3 as test do coveralls send || /bin/true) + +notifications: + webhooks: https://coveralls.io/webhook diff --git a/include/gtp_packet.hrl b/include/gtp_packet.hrl index 2dc6ee4..80de07d 100644 --- a/include/gtp_packet.hrl +++ b/include/gtp_packet.hrl @@ -79,7 +79,9 @@ rai, tai, ecgi, - lai + lai, + macro_enb, + ext_macro_enb }). -record(v2_fully_qualified_tunnel_endpoint_identifier, { @@ -90,12 +92,63 @@ ipv6 }). --record(v2_serving_network, { +-record(v2_fully_qualified_pdn_connection_set_identifier, { instance = 0, - mcc, - mnc + node_id_type = 0, + node_id, + csids = [] + }). + +-record(v2_private_extension, { + instance = 0, + enterprise_id = 0, + value = <<>> + }). + +-record(v2_twan_identifier, { + instance = 0, + ssid = <<>>, + bssid, + civic_address, + plmn_id, + operator_name, + relay_identity_type, + relay_identity, + circuit_id + }). + +-record(v2_paging_and_service_information, { + instance = 0, + ebi = 0, + ppi + }). + +-record(v2_integer_number, { + instance = 0, + width = 0, + value = 0 + }). + +-record(v2_remote_user_id, { + instance = 0, + imsi = <<>>, + msisdn, + imei + }). + +-record(v2_maximum_packet_loss_rate, { + instance = 0, + ul, + dl }). +-record(v2_monitoring_event_extension_information, { + instance = 0, + scef_reference_id = 0, + scef_id = <<>>, + remaining_minimum_lrtp +}). + %% -include("gtp_packet_v1_gen.hrl"). -record(cause, { @@ -701,7 +754,8 @@ v2_cause = reserved, pce = 0, bce = 0, - cs = 0 + cs = 0, + offending_ie }). -record(v2_recovery, { @@ -746,7 +800,7 @@ -record(v2_indication, { instance = 0, - flags + flags = [] }). -record(v2_protocol_configuration_options, { @@ -773,7 +827,12 @@ }). -record(v2_flow_quality_of_service, { - instance = 0 + instance = 0, + label = 0, + maximum_bit_rate_for_uplink = 0, + maximum_bit_rate_for_downlink = 0, + guaranteed_bit_rate_for_uplink = 0, + guaranteed_bit_rate_for_downlink = 0 }). -record(v2_rat_type, { @@ -781,35 +840,52 @@ rat_type = 0 }). +-record(v2_serving_network, { + instance = 0, + mcc = <<"001">>, + mnc = <<"001">> +}). -record(v2_eps_bearer_level_traffic_flow_template, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_traffic_aggregation_description, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_tmsi, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_global_cn_id, { - instance = 0 + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + value = <<>> }). -record(v2_s103_pdn_data_forwarding_info, { - instance = 0 + instance = 0, + hsgw_address = <<>>, + gre_key = 0, + eps_bearer_id = [] }). -record(v2_s1_u_data_forwarding_info, { - instance = 0 + instance = 0, + service_gw_address = <<>>, + teid = 0 }). -record(v2_delay_value, { - instance = 0 + instance = 0, + delay = 0 }). -record(v2_bearer_context, { @@ -828,11 +904,20 @@ }). -record(v2_trace_information, { - instance = 0 + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + trace_id = 0, + triggering_events = <<0,0,0,0,0,0,0,0,0>>, + list_of_ne_types = 0, + session_trace_depth = 0, + list_of_interfaces = <<0,0,0,0,0,0,0,0,0,0,0,0>>, + ip_address_of_trace_collection_entity = <<>> }). -record(v2_bearer_flags, { - instance = 0 + instance = 0, + flags = [] }). -record(v2_pdn_type, { @@ -841,7 +926,8 @@ }). -record(v2_procedure_transaction_id, { - instance = 0 + instance = 0, + pti = 0 }). -record(v2_mm_context_1, { @@ -869,23 +955,32 @@ }). -record(v2_pdn_connection, { - instance = 0 + instance = 0, + group }). -record(v2_pdu_numbers, { - instance = 0 + instance = 0, + nsapi = 0, + dl_gtp_u_sequence_number = 0, + ul_gtp_u_sequence_number = 0, + send_n_pdu_number = 0, + receive_n_pdu_number = 0 }). -record(v2_p_tmsi, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_p_tmsi_signature, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_hop_counter, { - instance = 0 + instance = 0, + hop_counter = 0 }). -record(v2_ue_time_zone, { @@ -895,47 +990,77 @@ }). -record(v2_trace_reference, { - instance = 0 + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + id = 0 }). -record(v2_complete_request_message, { - instance = 0 + instance = 0, + type = 0, + message = <<>> }). -record(v2_guti, { - instance = 0 + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + group_id = 0, + code = 0, + m_tmsi = <<>> }). -record(v2_f_container, { - instance = 0 + instance = 0, + type = 0, + data = <<>> }). -record(v2_f_cause, { - instance = 0 + instance = 0, + type = 0, + data = <<>> }). -record(v2_plmn_id, { - instance = 0 + instance = 0, + id = <<0,0,0>> }). -record(v2_target_identification, { - instance = 0 + instance = 0, + type = 0, + data = <<>> }). --record(v2_packet_flow_id_, { - instance = 0 +-record(v2_packet_flow_id, { + instance = 0, + ebi = 0, + flow_id = <<>> }). --record(v2_rab_context_, { - instance = 0 +-record(v2_rab_context, { + instance = 0, + ulpsi = 0, + dlpsi = 0, + ulgsi = 0, + dlgsi = 0, + nsapi = 0, + dl_gtp_u_sequence_number = 0, + ul_gtp_u_sequence_number = 0, + dl_pdcp_number = 0, + ul_pdcp_number = 0 }). -record(v2_source_rnc_pdcp_context_info, { - instance = 0 + instance = 0, + rrc_container = <<>> }). -record(v2_udp_source_port_number, { - instance = 0 + instance = 0, + port = 0 }). -record(v2_apn_restriction, { @@ -949,7 +1074,10 @@ }). -record(v2_source_identification, { - instance = 0 + instance = 0, + target_cell_id = <<>>, + source_type = 0, + source_id = <<>> }). -record(v2_change_reporting_action, { @@ -957,20 +1085,20 @@ action = stop_reporting }). --record(v2_fully_qualified_pdn_connection_set_identifier, { - instance = 0 -}). -record(v2_channel_needed, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_emlpp_priority, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_node_type, { - instance = 0 + instance = 0, + node_type = 0 }). -record(v2_fully_qualified_domain_name, { @@ -979,7 +1107,8 @@ }). -record(v2_transaction_identifier, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_mbms_session_duration, { @@ -1007,39 +1136,53 @@ }). -record(v2_rfsp_index, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_user_csg_information, { - instance = 0 + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + csg_id = <<0,0,0,0:3>>, + access_mode = 0, + lcsg = false, + cmi = 0 }). -record(v2_csg_information_reporting_action, { - instance = 0 + instance = 0, + actions = [] }). -record(v2_csg_id, { - instance = 0 + instance = 0, + id = <<0,0,0,0:3>> }). -record(v2_csg_membership_indication, { - instance = 0 + instance = 0, + cmi = 0 }). -record(v2_service_indicator, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_detach_type, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_local_distiguished_name, { - instance = 0 + instance = 0, + value = <<>> }). -record(v2_node_features, { - instance = 0 + instance = 0, + features = [] }). -record(v2_mbms_time_to_data_transfer, { @@ -1047,19 +1190,28 @@ }). -record(v2_throttling, { - instance = 0 + instance = 0, + unit = 0, + value = 0, + factor = 0 }). -record(v2_allocation_retention_priority, { - instance = 0 + instance = 0, + pci = false, + pl = 0, + pvi = false }). -record(v2_epc_timer, { - instance = 0 + instance = 0, + unit = 0, + value = 0 }). -record(v2_signalling_priority_indication, { - instance = 0 + instance = 0, + indication = [] }). -record(v2_temporary_mobile_group_identity, { @@ -1067,11 +1219,15 @@ }). -record(v2_additional_mm_context_for_srvcc, { - instance = 0 + instance = 0, + classmark_2 = <<>>, + classmark_3 = <<>>, + codec_list = <<>> }). -record(v2_additional_flags_for_srvcc, { - instance = 0 + instance = 0, + flags = [] }). -record(v2_mdt_configuration, { @@ -1079,7 +1235,8 @@ }). -record(v2_additional_protocol_configuration_options, { - instance = 0 + instance = 0, + config }). -record(v2_absolute_time_of_mbms_data_transfer, { @@ -1087,27 +1244,30 @@ }). -record(v2_henb_information_reporting_, { - instance = 0 + instance = 0, + flags = [] }). -record(v2_ipv4_configuration_parameters, { - instance = 0 + instance = 0, + prefix_length = 0, + default_route = <<0,0,0,0>> }). -record(v2_change_to_report_flags_, { - instance = 0 + instance = 0, + flags = [] }). -record(v2_action_indication, { - instance = 0 + instance = 0, + indication = 0 }). --record(v2_twan_identifier, { - instance = 0 -}). -record(v2_uli_timestamp, { - instance = 0 + instance = 0, + timestamp = 0 }). -record(v2_mbms_flags, { @@ -1115,23 +1275,31 @@ }). -record(v2_ran_nas_cause, { - instance = 0 + instance = 0, + protocol = 0, + type = 0, + cause = <<>> }). -record(v2_cn_operator_selection_entity, { - instance = 0 + instance = 0, + entity = 0 }). -record(v2_trusted_wlan_mode_indication, { - instance = 0 + instance = 0, + indication = [] }). -record(v2_node_number, { - instance = 0 + instance = 0, + number = <<>> }). -record(v2_node_identifier, { - instance = 0 + instance = 0, + name = <<>>, + realm = <<>> }). -record(v2_presence_reporting_area_action, { @@ -1143,33 +1311,147 @@ }). -record(v2_twan_identifier_timestamp, { - instance = 0 + instance = 0, + timestamp = 0 }). -record(v2_overload_control_information, { - instance = 0 + instance = 0, + group }). -record(v2_load_control_information, { - instance = 0 + instance = 0, + group }). -record(v2_metric, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_sequence_number, { - instance = 0 + instance = 0, + value = 0 }). -record(v2_apn_and_relative_capacity, { - instance = 0 + instance = 0, + capacity = 0, + apn = <<>> }). -record(v2_wlan_offloadability_indication, { - instance = 0 + instance = 0, + indication = [] }). --record(v2_private_extension, { + + +-record(v2_millisecond_time_stamp, { + instance = 0, + timestamp = 0 +}). + +-record(v2_monitoring_event_information, { instance = 0 }). + +-record(v2_ecgi_list, { + instance = 0, + ecgis = [] +}). + +-record(v2_remote_ue_context, { + instance = 0, + group +}). + + +-record(v2_remote_ue_ip_information, { + instance = 0, + ip = <<>> +}). + +-record(v2_ciot_optimizations_support_indication, { + instance = 0, + indication = [] +}). + +-record(v2_scef_pdn_connection, { + instance = 0, + group +}). + +-record(v2_header_compression_configuration, { + instance = 0, + rohc_profiles = 0, + max_cid = 0 +}). + +-record(v2_extended_protocol_configuration_options, { + instance = 0, + config +}). + +-record(v2_serving_plmn_rate_control, { + instance = 0, + uplink = 0, + downlink = 0 +}). + +-record(v2_counter, { + instance = 0, + timestamp = 0, + counter = 0 +}). + +-record(v2_mapped_ue_usage_type, { + instance = 0, + usage_type = 0 +}). + +-record(v2_secondary_rat_usage_data_report, { + instance = 0, + irsgw = false, + irpgw = false, + rat_type = 0, + ebi = 0, + start_time = 0, + end_time = 0, + dl = 0, + ul = 0 +}). + +-record(v2_up_function_selection_indication_flags, { + instance = 0, + indication = [] +}). + + +-record(v2_apn_rate_control_status, { + instance = 0, + number_of_uplink_packets_allowed = 0, + number_of_additional_exception_reports = 0, + number_of_downlink_packets_allowed = 0, + apn_rate_control_status_validity_time = 0 +}). + +-record(v2_extended_trace_information, { + instance = 0, + mcc = <<"001">>, + mnc = <<"001">>, + trace_id = 0, + triggering_events = <<>>, + list_of_ne_types = <<>>, + session_trace_depth = 0, + list_of_interfaces = <<>>, + ip_address_of_trace_collection_entity = <<>> +}). + + +-record(v2_additional_rrm_policy_index, { + instance = 0, + value = 0 +}). + diff --git a/priv/ie_gen_v2.erl b/priv/ie_gen_v2.erl index 4a6dd01..481176d 100755 --- a/priv/ie_gen_v2.erl +++ b/priv/ie_gen_v2.erl @@ -7,11 +7,11 @@ -define(V1_TAG, <<"%% -include(\"gtp_packet_v1_gen.hrl\").">>). -define(V2_TAG, <<"%% -include(\"gtp_packet_v2_gen.hrl\").">>). -ies() -> +raw_ies() -> [ {1, "v2 International Mobile Subscriber Identity", [{"IMSI", 0, {type, tbcd}}]}, - {2, "v2 Cause", + {2, "v2 Cause", 5, [{"v2 Cause", 8, {enum, [{1, "Reserved"}, {2, "Local Detach"}, {3, "Complete Detach"}, @@ -82,11 +82,21 @@ ies() -> {116, "Multiple PDN connections for a given APN not allowed"}, {117, "Target access restricted for the subscriber"}, {119, "MME/SGSN refuses due to VPLMN Policy"}, - {120, "GTP-C Entity Congestion"}]}}, + {120, "GTP-C Entity Congestion"}, + {121, "Late Overlapping Request"}, + {122, "Timed out Request"}, + {123, "UE is temporarily not reachable due to power saving"}, + {124, "Relocation failure due to NAS message redirection"}, + {125, "UE not authorised by OCS or external AAA Server"}, + {126, "Multiple accesses to a PDN connection not allowed"}, + {127, "Request rejected due to UE capability"}, + {128, "S1-U Path Failure"}, + {129, "5GC not allowed"}]}}, {'_', 5}, {"PCE", 1, integer}, {"BCE", 1, integer}, {"CS", 1, integer}, + {"offending IE", 4, bytes}, {'_', 0}]}, {3, "v2 Recovery", [{"Restart counter", 8, integer}, @@ -96,8 +106,7 @@ ies() -> [{"APN", 0, {type, fqdn}}]}, {72, "v2 Aggregate Maximum Bit Rate", [{"Uplink", 32, integer}, - {"Downlink", 32, integer}, - {'_', 0}]}, + {"Downlink", 32, integer}]}, {73, "v2 EPS Bearer ID", [{'_', 4}, {"EPS Bearer ID", 4, integer}, @@ -109,7 +118,15 @@ ies() -> {76, "v2 MSISDN", [{"MSISDN", 0, {type, tbcd}}]}, {77, "v2 Indication", - [{"Flags", 0, {type, v2_indication_flags}}]}, + [{"Flags", 0, + {flags, ['DAF', 'DTF', 'HI', 'DFI', 'OI', 'ISRSI', 'ISRAI', 'SGWCI', + 'SQCI', 'UIMSI', 'CFSI', 'CRSI', 'P', 'PT', 'SI', 'MSV', + 'RetLoc', 'PBIC', 'SRNI', 'S6AF', 'S4AF', 'MBMDT', 'ISRAU', 'CCRSI', + 'CPRAI', 'ARRL', 'PPOF', 'PPON/PPEI', 'PPSI', 'CSFBI', 'CLII', 'CPSR', + 'NSI', 'UASI', 'DTCI', 'BDWI', 'PSCI', 'PCRI', 'AOSI', 'AOPI', + 'ROAAI', 'EPCOSI', 'CPOPCI', 'PMTSMI', 'S11TF', 'PNSI', 'UNACCSI', 'WPMSI', + '5GSNN26', 'REPREFI', '5GSIWK', 'EEVRSI', 'LTEMUI', 'LTEMPI', 'ENBCRSI', 'TSPCMI', + '_', '_', '_', 'N5GNMI', '5GCNRS', '5GCNRI', '5SRHOI', 'ETHPDN']}}]}, {78, "v2 Protocol Configuration Options", [{"Config", protocol_config_opts}]}, {79, "v2 PDN Address Allocation", @@ -117,7 +134,8 @@ ies() -> {"Type", 3, {enum, [{1, "IPv4"}, {2, "IPv6"}, {3, "IPv4v6"}, - {4, "Non-IP"}]}}, + {4, "Non-IP"}, + {5, "Ethernet"}]}}, {"Address", 0, binary}]}, {80, "v2 Bearer Level Quality of Service", [{'_', 1}, @@ -131,28 +149,58 @@ ies() -> {"Guaranteed bit rate for uplink", 40, integer}, {"Guaranteed bit rate for downlink", 40, integer}, {'_', 0}]}, - {81, "v2 Flow Quality of Service", []}, + {81, "v2 Flow Quality of Service", + [{"Label", 8, integer}, + {"Maximum bit rate for uplink", 40, integer}, + {"Maximum bit rate for downlink", 40, integer}, + {"Guaranteed bit rate for uplink", 40, integer}, + {"Guaranteed bit rate for downlink", 40, integer}, + {'_', 0}]}, {82, "v2 RAT Type", [{"RAT Type", 8, integer}, {'_', 0}]}, - {83, "v2 Serving Network", v2_mccmnc}, - {84, "v2 EPS Bearer Level Traffic Flow Template", []}, - {85, "v2 Traffic Aggregation Description", []}, + {83, "v2 Serving Network", + [{"MCCMNC", mccmnc}, + {'_', 0}]}, + {84, "v2 EPS Bearer Level Traffic Flow Template", + [{"Value", 0, binary}]}, + {85, "v2 Traffic Aggregation Description", + [{"Value", 0, binary}]}, {86, "v2 User Location Information", v2_user_location_information}, {87, "v2 Fully Qualified Tunnel Endpoint Identifier", v2_fully_qualified_tunnel_endpoint_identifier}, - {88, "v2 TMSI", []}, - {89, "v2 Global CN-Id", []}, - {90, "v2 S103 PDN Data Forwarding Info", []}, - {91, "v2 S1-U Data Forwarding Info", []}, - {92, "v2 Delay Value", []}, + {88, "v2 TMSI", + [{"Value", 32, integer}]}, + {89, "v2 Global CN-Id", + [{"MCCMNC", mccmnc}, + {"Value", 0, binary}]}, + {90, "v2 S103 PDN Data Forwarding Info", + [{"HSGW Address", 8, length_binary}, + {"GRE Key", 32, integer}, + {"EPS Bearer Id", 8, {array, {8, integer}}}]}, + {91, "v2 S1-U Data Forwarding Info", + [{"Service GW Address", 8, length_binary}, + {"TEID", 32, integer}]}, + {92, "v2 Delay Value", + [{"Delay", 8, integer}, + {'_', 0}]}, {93, "v2 Bearer Context", [{"Group", 0, {type, v2_grouped}}]}, {94, "v2 Charging ID", - [{id, 4, bytes}]}, + [{"Id", 4, bytes}, + {'_', 0}]}, {95, "v2 Charging Characteristics", - [{"Value", 2, bytes}]}, - {96, "v2 Trace Information", []}, - {97, "v2 Bearer Flags", []}, + [{"Value", 2, bytes}, + {'_', 0}]}, + {96, "v2 Trace Information", + [{"MCCMNC", mccmnc}, + {"Trace ID", 32, integer}, + {"Triggering Events", 9, bytes}, + {"List of NE Types", 16, integer}, + {"Session Trace Depth", 8, integer}, + {"List of Interfaces", 12, bytes}, + {"IP Address of Trace Collection Entity", 0, binary}]}, + {97, "v2 Bearer Flags", + [{"Flags", 0, {flags, ['_', '_', '_', '_', 'ASI', 'Vind', 'VB', 'PCC']}}]}, {99, "v2 PDN Type", [{'_', 4}, {"PDN Type", 4, {enum, [{1, "IPv4"}, @@ -160,34 +208,80 @@ ies() -> {3, "IPv4v6"}, {4, "Non-IP"}]}}, {'_', 0}]}, - {100, "v2 Procedure Transaction ID", []}, + {100, "v2 Procedure Transaction ID", + [{"PTI", 8, integer}, + {'_', 0}]}, {103, "v2 MM Context 1", []}, {104, "v2 MM Context 2", []}, {105, "v2 MM Context 3", []}, {106, "v2 MM Context 4", []}, {107, "v2 MM Context 5", []}, {108, "v2 MM Context 6", []}, - {109, "v2 PDN Connection", []}, - {110, "v2 PDU Numbers", []}, - {111, "v2 P-TMSI", []}, - {112, "v2 P-TMSI Signature", []}, - {113, "v2 Hop Counter", []}, + {109, "v2 PDN Connection", + [{"Group", 0, {type, v2_grouped}}]}, + {110, "v2 PDU Numbers", + [{'_', 4}, + {"NSAPI", 4, integer}, + {"DL GTP-U Sequence Number", 16, integer}, + {"UL GTP-U Sequence Number", 16, integer}, + {"Send N-PDU Number", 16, integer}, + {"Receive N-PDU Number", 16, integer}, + {'_', 0}]}, + {111, "v2 P-TMSI", + [{"Value", 0, binary}]}, + {112, "v2 P-TMSI Signature", + [{"Value", 0, binary}]}, + {113, "v2 Hop Counter", + [{"Hop Counter", 8, integer}, + {'_', 0}]}, {114, "v2 UE Time Zone", [{"TimeZone", 8, integer}, {'_', 6}, {"DST", 2, integer}, {'_', 0}]}, - {115, "v2 Trace Reference", []}, - {116, "v2 Complete Request Message", []}, - {117, "v2 GUTI", []}, - {118, "v2 F-Container", []}, - {119, "v2 F-Cause", []}, - {120, "v2 PLMN ID", []}, - {121, "v2 Target Identification", []}, - {123, "v2 Packet Flow ID ", []}, - {124, "v2 RAB Context ", []}, - {125, "v2 Source RNC PDCP Context Info", []}, - {126, "v2 UDP Source Port Number", []}, + {115, "v2 Trace Reference", + [{"MCCMNC", mccmnc}, + {"Id", 24, integer}]}, + {116, "v2 Complete Request Message", + [{"Type", 8, integer}, + {"Message", 0, binary}]}, + {117, "v2 GUTI", + [{"MCCMNC", mccmnc}, + {"Group Id", 16, integer}, + {"Code", 24, integer}, + {"M-TMSI", 0, binary}]}, + {118, "v2 F-Container", + [{'_', 4}, + {"Type", 4, integer}, + {"Data", 0, binary}]}, + {119, "v2 F-Cause", + [{'_', 4}, + {"Type", 4, integer}, + {"Data", 0, binary}]}, + {120, "v2 PLMN ID", + [{"Id", 3, bytes}]}, + {121, "v2 Target Identification", + [{"Type", 8, integer}, + {"Data", 0, binary}]}, + {123, "v2 Packet Flow ID", + [{'_', 4}, + {"EBI", 4, integer}, + {"Flow Id", 0, binary}]}, + {124, "v2 RAB Context", + [{"ULPSI", 1, integer}, + {"DLPSI", 1, integer}, + {"ULGSI", 1, integer}, + {"DLGSI", 1, integer}, + {"NSAPI", 4, integer}, + {"DL GTP-U Sequence Number", 16, integer}, + {"UL GTP-U Sequence Number", 16, integer}, + {"DL PDCP Number", 16, integer}, + {"UL PDCP Number", 16, integer}]}, + {125, "v2 Source RNC PDCP Context Info", + [{"RRC Container", 0, binary}]}, + {126, "v2 UDP Source Port Number", + [{"Port", 16, integer}, + {'_', 0}]}, {127, "v2 APN Restriction", [{"Restriction Type Value", 8, integer}, {'_', 0}]}, @@ -195,7 +289,10 @@ ies() -> [{'_', 6}, {"Mode", 2, integer}, {'_', 0}]}, - {129, "v2 Source Identification", []}, + {129, "v2 Source Identification", + [{"Target Cell Id", 8, binary}, + {"Source Type", 8, integer}, + {"Source Id", 0, binary}]}, {131, "v2 Change Reporting Action", [{"Action", 8, {enum, [{0, "Stop Reporting"}, {1, "Start Reporting CGI/SAI"}, @@ -208,61 +305,207 @@ ies() -> {8, "Start Reporting TAI, Macro eNodeB ID and Extended Macro eNodeB ID"} ]}}, {'_', 0}]}, - {132, "v2 Fully Qualified PDN Connection Set Identifier", []}, - {133, "v2 Channel needed", []}, - {134, "v2 eMLPP Priority", []}, - {135, "v2 Node Type", []}, + {132, "v2 Fully Qualified PDN Connection Set Identifier", + v2_fully_qualified_pdn_connection_set_identifier}, + {133, "v2 Channel needed", + [{"Value", 0, binary}]}, + {134, "v2 eMLPP Priority", + [{"Value", 0, binary}]}, + {135, "v2 Node Type", + [{"Node Type", 8, integer}, + {'_', 0}]}, {136, "v2 Fully Qualified Domain Name", [{"FQDN", 0, {type, fqdn}}]}, - {137, "v2 Transaction Identifier", []}, + {137, "v2 Transaction Identifier", + [{"Value", 0, binary}]}, {138, "v2 MBMS Session Duration", []}, {139, "v2 MBMS Service Area", []}, {140, "v2 MBMS Session Identifier", []}, {141, "v2 MBMS Flow Identifier", []}, {142, "v2 MBMS IP Multicast Distribution", []}, {143, "v2 MBMS Distribution Acknowledge", []}, - {144, "v2 RFSP Index", []}, - {145, "v2 User CSG Information", []}, - {146, "v2 CSG Information Reporting Action", []}, - {147, "v2 CSG ID", []}, - {148, "v2 CSG Membership Indication", []}, - {149, "v2 Service indicator", []}, - {150, "v2 Detach Type", []}, - {151, "v2 Local Distiguished Name", []}, - {152, "v2 Node Features", []}, + {144, "v2 RFSP Index", + [{"Value", 16, integer}]}, + {145, "v2 User CSG Information", + [{"MCCMNC", mccmnc}, + {'_', 5}, + {"CSG Id", 27, bits}, + {"Access mode", 2, integer}, + {'_', 4}, + {"LCSG", 1, boolean}, + {"CMI", 1, integer}]}, + {146, "v2 CSG Information Reporting Action", + [{"Actions", 0, {flags, ['_', '_', '_', '_', '_', 'UCIUHC', 'UCISHC', 'UCICSG']}}]}, + {147, "v2 CSG ID", + [{'_', 5}, + {"Id", 27, bits}, + {'_', 0}]}, + {148, "v2 CSG Membership Indication", + [{'_', 7}, + {"CMI", 1, integer}, + {'_', 0}]}, + {149, "v2 Service indicator", + [{"Value", 8, integer}]}, + {150, "v2 Detach Type", + [{"Value", 8, integer}]}, + {151, "v2 Local Distiguished Name", + [{"Value", 0, binary}]}, + {152, "v2 Node Features", + [{"Features", 0, {flags, ['_', '_', 'ETH', 'S1UN', 'CIOT', 'NTSR', 'MABR', 'PRN']}}]}, {153, "v2 MBMS Time to Data Transfer", []}, - {154, "v2 Throttling", []}, - {155, "v2 Allocation/Retention Priority", []}, - {156, "v2 EPC Timer", []}, - {157, "v2 Signalling Priority Indication", []}, + {154, "v2 Throttling", + [{"Unit", 3, integer}, + {"Value", 5, integer}, + {"Factor", 8, integer}, + {'_', 0}]}, + {155, "v2 Allocation/Retention Priority", + [{'_', 1}, + {"PCI", 1, boolean}, + {"PL", 4, integer}, + {'_', 1}, + {"PVI", 1, boolean}, + {'_', 0}]}, + {156, "v2 EPC Timer", + [{"Unit", 3, integer}, + {"Value", 5, integer}, + {'_', 0}]}, + {157, "v2 Signalling Priority Indication", + [{"Indication", 0, {flags, ['_', '_', '_', '_', '_', '_', '_', 'LAPI']}}]}, {158, "v2 Temporary Mobile Group Identity", []}, - {159, "v2 Additional MM context for SRVCC", []}, - {160, "v2 Additional flags for SRVCC", []}, + {159, "v2 Additional MM context for SRVCC", + [{"Classmark 2", 8, length_binary}, + {"Classmark 3", 8, length_binary}, + {"Codec List", 8, length_binary}, + {'_', 0}]}, + {160, "v2 Additional flags for SRVCC", + [{"Flags", 0, {flags, ['_', '_', '_', '_', '_', '_', 'VF', 'ICS']}}]}, {162, "v2 MDT Configuration", []}, - {163, "v2 Additional Protocol Configuration Options", []}, + {163, "v2 Additional Protocol Configuration Options", + [{"Config", protocol_config_opts}]}, {164, "v2 Absolute Time of MBMS Data Transfer", []}, - {165, "v2 HeNB Information Reporting ", []}, - {166, "v2 IPv4 Configuration Parameters", []}, - {167, "v2 Change to Report Flags ", []}, - {168, "v2 Action Indication", []}, - {169, "v2 TWAN Identifier", []}, - {170, "v2 ULI Timestamp", []}, + {165, "v2 HeNB Information Reporting ", + [{"Flags", 0, {flags, ['_', '_', '_', '_', '_', '_', '_', 'FTI']}}]}, + {166, "v2 IPv4 Configuration Parameters", + [{"Prefix Length", 8, integer}, + {"Default Route", 4, bytes}, + {'_', 0}]}, + {167, "v2 Change to Report Flags ", + [{"Flags", 0, {flags, ['_', '_', '_', '_', '_', '_', 'TZCR', 'SNCR']}}]}, + {168, "v2 Action Indication", + [{'_', 5}, + {"Indication", 3, integer}, + {'_', 0}]}, + {169, "v2 TWAN Identifier", v2_twan_identifier}, + {170, "v2 ULI Timestamp", + [{"Timestamp", 32, integer}, + {'_', 0}]}, {171, "v2 MBMS Flags", []}, - {172, "v2 RAN/NAS Cause", []}, - {173, "v2 CN Operator Selection Entity", []}, - {174, "v2 Trusted WLAN Mode Indication", []}, - {175, "v2 Node Number", []}, - {176, "v2 Node Identifier", []}, + {172, "v2 RAN/NAS Cause", + [{"Protocol", 4, integer}, + {"Type", 4, integer}, + {"Cause", 0, binary}]}, + {173, "v2 CN Operator Selection Entity", + [{'_', 6}, + {"Entity", 2, integer}, + {'_', 0}]}, + {174, "v2 Trusted WLAN Mode Indication", + [{"Indication", 0, {flags, ['_', '_', '_', '_', '_', '_', 'MCM', 'SCM']}}]}, + {175, "v2 Node Number", + [{"Number", 8, length_binary}, %% TBD: ISDN string + {'_', 0}]}, + {176, "v2 Node Identifier", + [{"Name", 8, length_binary}, + {"Realm", 8, length_binary}, + {'_', 0}]}, {177, "v2 Presence Reporting Area Action", []}, {178, "v2 Presence Reporting Area Information", []}, - {179, "v2 TWAN Identifier Timestamp", []}, - {180, "v2 Overload Control Information", []}, - {181, "v2 Load Control Information", []}, - {182, "v2 Metric", []}, - {183, "v2 Sequence Number", []}, - {184, "v2 APN and Relative Capacity", []}, - {185, "v2 WLAN Offloadability Indication", []}, - {255, "v2 Private Extension", []}]. + {179, "v2 TWAN Identifier Timestamp", + [{"Timestamp", 32, integer}, + {'_', 0}]}, + {180, "v2 Overload Control Information", + [{"Group", 0, {type, v2_grouped}}]}, + {181, "v2 Load Control Information", + [{"Group", 0, {type, v2_grouped}}]}, + {182, "v2 Metric", + [{"Value", 8, integer}]}, + {183, "v2 Sequence Number", + [{"Value", 32, integer}]}, + {184, "v2 APN and Relative Capacity", + [{"Capacity", 8, integer}, + {"APN", 8, length_binary}, %% TBD: APN encoding + {'_', 0}]}, + {185, "v2 WLAN Offloadability Indication", + [{"Indication", 0, {flags, ['_', '_', '_', '_', '_', '_', 'EUTRAN', 'UTRAN']}}]}, + {186, "v2 Paging and Service Information", v2_paging_and_service_information}, + {187, "v2 Integer Number", v2_integer_number}, + {188, "v2 Millisecond Time Stamp", + [{"Timestamp", 48, integer}, + {'_', 0}]}, + {189, "v2 Monitoring Event Information", []}, % WTF: flags encoded in the spare bits + % of the Instance field + {190, "v2 ECGI List", + [{"ECGIs", 16, {array, {7, bytes}}}, + {'_', 0}]}, + {191, "v2 Remote UE Context", + [{"Group", 0, {type, v2_grouped}}]}, + {192, "v2 Remote User ID", v2_remote_user_id}, + {193, "v2 Remote UE IP information", + [{"IP", 0, binary}]}, + {194, "v2 CIoT Optimizations Support Indication", + [{"Indication", 0, {flags, ['_', '_', '_', '_', 'IHCSI', 'AWOPDN', 'SCNIPDN', 'SGNIPDN']}}]}, + {195, "v2 SCEF PDN Connection", + [{"Group", 0, {type, v2_grouped}}]}, + {196, "v2 Header Compression Configuration", + [{"ROHC Profiles", 16, integer}, + {"MAX CID", 16, integer}, + {'_', 0}]}, + {197, "v2 Extended Protocol Configuration Options", + [{"Config", protocol_config_opts}]}, + {198, "v2 Serving PLMN Rate Control", + [{"Uplink", 16, integer}, + {"Downlink", 16, integer}, + {'_', 0}]}, + {199, "v2 Counter", + [{"Timestamp", 32, integer}, + {"Counter", 8, integer}, + {'_', 0}]}, + {200, "v2 Mapped UE Usage Type", + [{"Usage Type", 16, integer}, + {'_', 0}]}, + {201, "v2 Secondary RAT Usage Data Report", + [{'_', 6}, + {"IRSGW", 1, boolean}, + {"IRPGW", 1, boolean}, + {"RAT Type", 8, integer}, + {'_', 4}, + {"EBI", 4, integer}, + {"Start Time", 32, integer}, + {"End Time", 32, integer}, + {"DL", 64, integer}, + {"UL", 64, integer}, + {'_', 0}]}, + {202, "v2 UP Function Selection Indication Flags", + [{"Indication", 0, {flags, ['_', '_', '_', '_', '_', '_', '_', 'DCNR']}}]}, + {203, "v2 Maximum Packet Loss Rate", v2_maximum_packet_loss_rate}, + {204, "v2 APN Rate Control Status", + [{"Number of Uplink packets allowed", 32, integer}, + {"Number of additional exception reports", 32, integer}, + {"Number of Downlink packets allowed", 32, integer}, + {"APN Rate Control Status validity Time", 64, integer}, + {'_', 0}]}, + {205, "v2 Extended Trace Information", + [{"MCCMNC", mccmnc}, + {"Trace ID", 32, integer}, + {"Triggering Events", 8, length_binary}, + {"List of NE Types", 8, length_binary}, + {"Session Trace Depth", 8, integer}, + {"List of Interfaces", 8, length_binary}, + {"IP Address of Trace Collection Entity", 8, length_binary}, + {'_', 0}]}, + {206, "v2 Monitoring Event Extension Information", v2_monitoring_event_extension_information}, + {207, "v2 Additional RRM Policy Index", + [{"Value", 32, integer}]}, + {255, "v2 Private Extension", v2_private_extension}]. msgs() -> [{1, "Echo Request"}, @@ -344,109 +587,195 @@ msgs() -> {236, "MBMS Session Stop Response"} ]. -gen_record_def({Value, _}) when is_integer(Value); is_atom(Value) -> +-type flag() :: any(). +-type enum() :: any(). +-type array_def() :: any(). +-type field_type() :: + {flags, [flag()]} | + {enum, [enum()]} | + boolean | + integer | + bits | + bytes | + binary | + length_binary | + {array, array_def()} | + tuple(). + +-record(ie, {id, name, type, min_field_count, fields}). +-record(field, {name, len, optional, type, spec}). + +-define('Instance', #field{name = 'instance', type = integer}). +-define('WildCard', #field{type = '_', len = 0}). +-define('DecoderFunName', "decode_v2_element"). +-define('EncoderFunName', "encode_v2_element"). + +ies() -> + TypeFF = fun(Type, F) when is_atom(Type) -> F#field{type = Type}; + ({type, Type}, F) when is_atom(Type) -> F#field{type = helper, spec = Type}; + ({array, Size}, F) when is_integer(Size) -> F#field{type = array, spec = {1, byte}}; + ({Type, Spec}, F) when is_atom(Type) -> F#field{type = Type, spec = Spec} + end, + FieldF = fun({Name, Len, Type}, Optional, F) when is_integer(Len) -> + [TypeFF(Type, #field{name = s2a(Name), len = Len, + optional = Optional}) | F]; + ({Name, Type}, Optional, F) when is_list(Name), is_atom(Type) -> + [#field{name = s2a(Name), len = 0, optional = Optional, + type = helper, spec = Type} | F]; + ({'_', Len}, Optional, F) when is_integer(Len) -> + [#field{len = Len, optional = Optional, type = '_'} | F] + end, + SpecF = fun(Fields, #ie{min_field_count = MinLen} = IE) when is_list(Fields) -> + {FieldDef, _} = + lists:foldl( + fun(Field, {F, Cnt}) -> + {FieldF(Field, Cnt >= MinLen, F), Cnt + 1} end, + {[], 0}, Fields), + IE#ie{fields = lists:reverse(FieldDef)}; + (Helper, IE) when is_atom(Helper) -> + IE#ie{type = Helper} + end, + lists:map( + fun ({Id, Name, Spec}) -> + SpecF(Spec, #ie{id = Id, name = s2a(Name)}); + ({Id, Name, MinLen, Spec}) -> + SpecF(Spec, #ie{id = Id, name = s2a(Name), min_field_count = MinLen}) + end, raw_ies()). + +%% gen_record_def({Value, _}) when is_integer(Value); is_atom(Value) -> + +%% gen_record_def(#field{len = undefined}) -> +%% []; +gen_record_def(#field{type = '_'}) -> []; -gen_record_def({Name, {flags, _}}) -> - [io_lib:format("~s = []", [s2a(Name)])]; -gen_record_def({Name, _, {enum, [{_,H}|_]}}) -> - [io_lib:format("~s = ~s", [s2a(Name), s2a(H)])]; -gen_record_def({Name, _, {enum, [H|_]}}) -> - [io_lib:format("~s = ~s", [s2a(Name), s2a(H)])]; -gen_record_def({Name, _, integer}) -> - [io_lib:format("~s = 0", [s2a(Name)])]; -gen_record_def({Name, Size, bits}) -> - [io_lib:format("~s = ~w", [s2a(Name), <<0:Size>>])]; -gen_record_def({Name, Size, bytes}) -> - [io_lib:format("~s = ~w", [s2a(Name), <<0:(Size * 8)>>])]; -gen_record_def({Name, _, binary}) -> - [io_lib:format("~s = <<>>", [s2a(Name)])]; -gen_record_def({Name, _, length_binary}) -> - [io_lib:format("~s = <<>>", [s2a(Name)])]; -gen_record_def({Name, _, {array, _}}) -> - [io_lib:format("~s = []", [s2a(Name)])]; -gen_record_def(Tuple) -> - Name = element(1, Tuple), - [s2a(Name)]. - -gen_decoder_header_match({'_', 0}) -> +gen_record_def(#field{spec = mccmnc}) -> + ["mcc = <<\"001\">>", "mnc = <<\"001\">>"]; +gen_record_def(#field{name = Name, optional = true}) -> + [to_string(Name)]; +gen_record_def(#field{name = Name, type = flags}) -> + [io_lib:format("~s = []", [Name])]; +gen_record_def(#field{name = Name, type = enum, spec = [{_,H}|_]}) -> + [io_lib:format("~s = ~s", [Name, s2a(H)])]; +gen_record_def(#field{name = Name, type = enum, spec = [H|_]}) -> + [io_lib:format("~s = ~s", [Name, s2a(H)])]; +gen_record_def(#field{name = Name, type = boolean}) -> + [io_lib:format("~s = false", [Name])]; +gen_record_def(#field{name = Name, type = integer}) -> + [io_lib:format("~s = 0", [Name])]; +gen_record_def(#field{name = Name, len = Size, type = bits}) -> + [io_lib:format("~s = ~w", [Name, <<0:Size>>])]; +gen_record_def(#field{name = Name, len = Size, type = bytes}) -> + [io_lib:format("~s = ~w", [Name, <<0:(Size * 8)>>])]; +gen_record_def(#field{name = Name, type = binary}) -> + [io_lib:format("~s = <<>>", [Name])]; +gen_record_def(#field{name = Name, type = length_binary}) -> + [io_lib:format("~s = <<>>", [Name])]; +gen_record_def(#field{name = Name, type = array}) -> + [io_lib:format("~s = []", [Name])]; +gen_record_def(#field{name = Name}) -> + [to_string(Name)]. + +gen_decoder_header_match(#field{type = '_', len = 0}) -> ["_/binary"]; -gen_decoder_header_match({'_', Size}) -> +gen_decoder_header_match(#field{type = '_', len = Size}) -> [io_lib:format("_:~w", [Size])]; -gen_decoder_header_match({Value, Size}) when is_integer(Value); is_atom(Value) -> - [io_lib:format("~w:~w", [Value, Size])]; -gen_decoder_header_match({Name, {flags, Flags}}) -> - [io_lib:format("M_~s_~s:1", [s2a(Name), s2a(Flag)]) || Flag <- Flags]; -gen_decoder_header_match({Name, Size, {enum, _Enum}}) -> - [io_lib:format("M_~s:~w/integer", [s2a(Name), Size])]; -gen_decoder_header_match({Name, _Fun}) -> - [io_lib:format("M_~s/binary", [s2a(Name)])]; -gen_decoder_header_match({Name, _Len, {array, Multi}}) when is_list(Multi) -> - {stop, [io_lib:format("M_~s_Rest/binary", [s2a(Name)])]}; -gen_decoder_header_match({Name, Len, {array, _Multi}}) -> - {stop, [io_lib:format("M_~s_len:~w/integer, M_~s_Rest/binary", [s2a(Name), Len, s2a(Name)])]}; -gen_decoder_header_match({Name, Len, length_binary}) -> - [io_lib:format("M_~s_len:~w/integer, M_~s:M_~s_len/bytes", [s2a(Name), Len, s2a(Name), s2a(Name)])]; -gen_decoder_header_match({Name, 0, {type, _TypeName}}) -> - [io_lib:format("M_~s/binary", [s2a(Name)])]; -gen_decoder_header_match({Name, 0, Type}) -> - [io_lib:format("M_~s/~w", [s2a(Name), Type])]; -gen_decoder_header_match({Name, Size, {type, _TypeName}}) -> - [io_lib:format("M_~s:~w/bits", [s2a(Name), Size])]; -gen_decoder_header_match({Name, Size, Type}) -> - [io_lib:format("M_~s:~w/~s", [s2a(Name), Size, Type])]. - -gen_decoder_record_assign({Value, _}) when is_integer(Value); is_atom(Value) -> +%% gen_decoder_header_match(#field{Value, Size}) when is_integer(Value); is_atom(Value) -> +%% [io_lib:format("~w:~w", [Value, Size])]; +gen_decoder_header_match(#field{name = Name, spec = mccmnc}) -> + [io_lib:format("M_~s:3/bytes", [Name])]; +gen_decoder_header_match(#field{name = Name, type = flags}) -> + [io_lib:format("M_~s/binary", [Name])]; +gen_decoder_header_match(#field{name = Name, len = Size, type = enum}) -> + [io_lib:format("M_~s:~w/integer", [Name, Size])]; +gen_decoder_header_match(#field{name = Name, type = array, spec = Multi}) + when is_list(Multi) -> + {stop, [io_lib:format("M_~s_Rest/binary", [Name])]}; +gen_decoder_header_match(#field{name = Name, len = Len, type = array}) -> + {stop, [io_lib:format("M_~s_len:~w/integer, M_~s_Rest/binary", [Name, Len, Name])]}; +gen_decoder_header_match(#field{name = Name, len = Len, type = length_binary}) -> + [io_lib:format("M_~s_len:~w/integer, M_~s:M_~s_len/bytes", [Name, Len, Name, Name])]; +gen_decoder_header_match(#field{name = Name, len = 0, type = helper}) -> + [io_lib:format("M_~s/binary", [Name])]; +gen_decoder_header_match(#field{name = Name, len = Size, type = helper}) -> + [io_lib:format("M_~s:~w/bits", [Name, Size])]; +gen_decoder_header_match(#field{name = Name, len = Size, type = boolean}) -> + [io_lib:format("M_~s:~w/integer", [Name, Size])]; +gen_decoder_header_match(#field{name = Name, len = 0, type = Type}) -> + [io_lib:format("M_~s/~w", [Name, Type])]; +gen_decoder_header_match(#field{name = Name, len = Size, type = Type}) -> + [io_lib:format("M_~s:~w/~s", [Name, Size, Type])]. + +%% gen_decoder_record_assign(#field{Value, _}) when is_integer(Value); is_atom(Value) -> +%% []; +gen_decoder_record_assign(#field{type = '_'}) -> []; -gen_decoder_record_assign({Name, {flags, Flags}}) -> - F = [io_lib:format("[ '~s' || M_~s_~s =/= 0 ]", [X, s2a(Name), s2a(X)]) || X <- Flags], - [io_lib:format("~s = ~s", [s2a(Name), string:join(F, " ++ ")])]; -gen_decoder_record_assign({Name, _Size, {enum, _Enum}}) -> - [io_lib:format("~s = enum_v2_~s(M_~s)", [s2a(Name), s2a(Name), s2a(Name)])]; -gen_decoder_record_assign({Name, Fun}) -> - [io_lib:format("~s = decode_~s(M_~s)", [s2a(Name), Fun, s2a(Name)])]; -gen_decoder_record_assign({Name, Size, {array, Multi}}) when is_list(Multi) -> - [io_lib:format("~s = [X || <> <= M_~s]", [s2a(Name), Size, s2a(Name)])]; -gen_decoder_record_assign({Name, _Size, {array, Multi}}) -> - [io_lib:format("~s = [X || <> <= M_~s]", [s2a(Name), Multi, s2a(Name)])]; -gen_decoder_record_assign({Name, _Size, {type, TypeName}}) -> - [io_lib:format("~s = decode_~s(M_~s)", [s2a(Name), TypeName, s2a(Name)])]; -gen_decoder_record_assign({Name, _Size, _Type}) -> - [io_lib:format("~s = M_~s", [s2a(Name), s2a(Name)])]. - -gen_encoder_record_assign({Value, _}) when is_integer(Value); is_atom(Value) -> +gen_decoder_record_assign(#field{name = Name, spec = mccmnc}) -> + [io_lib:format("mcc = decode_mcc(M_~s)", [Name]), + io_lib:format("mnc = decode_mnc(M_~s)", [Name])]; +gen_decoder_record_assign(#field{name = Name, type = flags, spec = Flags}) -> + [io_lib:format("~s = decode_flags(binary:decode_unsigned(M_~s, little), ~p)", + [Name, Name, reorder_flags(Flags)])]; + +gen_decoder_record_assign(#field{name = Name, type = enum}) -> + [io_lib:format("~s = enum_v2_~s(M_~s)", [Name, Name, Name])]; +gen_decoder_record_assign(#field{name = Name, len = Size, type = array, spec = Multi}) + when is_list(Multi) -> + [io_lib:format("~s = [X || <> <= M_~s]", [Name, Size, Name])]; +gen_decoder_record_assign(#field{name = Name, type = array, spec = {Size, Type}}) -> + [io_lib:format("~s = [X || <> <= M_~s]", [Name, Size, Type, Name])]; +gen_decoder_record_assign(#field{name = Name, type = helper, spec = TypeName}) -> + [io_lib:format("~s = decode_~s(M_~s)", [Name, TypeName, Name])]; +gen_decoder_record_assign(#field{name = Name, type = boolean}) -> + [io_lib:format("~s = int2bool(M_~s)", [Name, Name])]; +gen_decoder_record_assign(#field{name = Name}) -> + [io_lib:format("~s = M_~s", [Name, Name])]. + +%% gen_encoder_record_assign({Value, _}) when is_integer(Value); is_atom(Value) -> +%% []; +gen_encoder_record_assign(#field{type = '_'}) -> []; -gen_encoder_record_assign(Tuple) -> - Name = element(1, Tuple), - [io_lib:format("~s = M_~s", [s2a(Name), s2a(Name)])]. - -gen_encoder_bin({'_', 0}) -> +gen_encoder_record_assign(#field{spec = mccmnc}) -> + ["mcc = M_mcc", "mnc = M_mnc"]; +gen_encoder_record_assign(#field{name = Name, type = undefined}) -> + [io_lib:format("~s = undefined", [Name])]; +gen_encoder_record_assign(#field{name = Name}) -> + [io_lib:format("~s = M_~s", [Name, Name])]. + +gen_encoder_bin(#field{type = '_', len = 0}) -> []; -gen_encoder_bin({'_', Size}) -> +gen_encoder_bin(#field{type = '_', len = Size}) -> [io_lib:format("0:~w", [Size])]; -gen_encoder_bin({Value, Size}) when is_integer(Value); is_atom(Value) -> - [io_lib:format("~w:~w", [Value, Size])]; -gen_encoder_bin({Name, {flags, Flags}}) -> - [io_lib:format("(encode_v2_flag('~s', M_~s)):1", [Flag, s2a(Name)]) || Flag <- Flags]; -gen_encoder_bin({Name, Size, {enum, _Enum}}) -> - [io_lib:format("(enum_v2_~s(M_~s)):~w/integer", [s2a(Name), s2a(Name), Size])]; -gen_encoder_bin({Name, Fun}) -> - [io_lib:format("(encode_~s(M_~s))/binary", [Fun, s2a(Name)])]; -gen_encoder_bin({Name, Len, {array, _Multi}}) -> - [io_lib:format("(length(M_~s)):~w/integer, (<< <> || X <- M_~s>>)/binary", [s2a(Name), Len, s2a(Name)])]; -gen_encoder_bin({Name, 0, {type, TypeName}}) -> - [io_lib:format("(encode_~s(M_~s))/binary", [TypeName, s2a(Name)])]; -gen_encoder_bin({Name, Size, {type, TypeName}}) -> - [io_lib:format("(encode_~s(M_~s)):~w/bits", [TypeName, s2a(Name), Size])]; -gen_encoder_bin({Name, Len, length_binary}) -> - [io_lib:format("(byte_size(M_~s)):~w/integer, M_~s/binary", [s2a(Name), Len, s2a(Name)])]; -gen_encoder_bin({Name, 0, Type}) -> - [io_lib:format("M_~s/~w", [s2a(Name), Type])]; -gen_encoder_bin({Name, Size, bytes}) -> - [io_lib:format("M_~s:~w/bytes", [s2a(Name), Size])]; -gen_encoder_bin({Name, Size, bits}) -> - [io_lib:format("M_~s:~w/bits", [s2a(Name), Size])]; -gen_encoder_bin({Name, Size, _Type}) -> - [io_lib:format("M_~s:~w", [s2a(Name), Size])]. + +%% gen_encoder_bin(#field{Value, Size}) when is_integer(Value); is_atom(Value) -> +%% [io_lib:format("~w:~w", [Value, Size])]; +gen_encoder_bin(#field{type = undefined}) -> + []; +gen_encoder_bin(#field{spec = mccmnc}) -> + ["(encode_mccmnc(M_mcc, M_mnc))/binary"]; +gen_encoder_bin(#field{name = Name, type = flags, spec = Flags}) -> + [io_lib:format("(binary:encode_unsigned(encode_flags(M_~s, ~p), little))/binary", + [Name, reorder_flags(Flags)])]; +gen_encoder_bin(#field{name = Name, len = Size, type = enum}) -> + [io_lib:format("(enum_v2_~s(M_~s)):~w/integer", [Name, Name, Size])]; +gen_encoder_bin(#field{name = Name, len = Len, type = array, spec = {Size, Type}}) -> + [io_lib:format("(length(M_~s)):~w/integer, (<< <> || X <- M_~s>>)/binary", + [Name, Len, Size, Type, Name])]; +gen_encoder_bin(#field{name = Name, len = Len, type = array}) -> + [io_lib:format("(length(M_~s)):~w/integer, (<< <> || X <- M_~s>>)/binary", [Name, Len, Name])]; +gen_encoder_bin(#field{name = Name, len = 0, type = helper, spec = TypeName}) -> + [io_lib:format("(encode_~s(M_~s))/binary", [TypeName, Name])]; +gen_encoder_bin(#field{name = Name, len = Size, type = helper, spec = TypeName}) -> + [io_lib:format("(encode_~s(M_~s)):~w/bits", [TypeName, Name, Size])]; +gen_encoder_bin(#field{name = Name, len = Len, type = length_binary}) -> + [io_lib:format("(byte_size(M_~s)):~w/integer, M_~s/binary", [Name, Len, Name])]; +gen_encoder_bin(#field{name = Name, len = 0, type = Type}) -> + [io_lib:format("M_~s/~w", [Name, Type])]; +gen_encoder_bin(#field{name = Name, len = Size, type = boolean}) -> + [io_lib:format("(bool2int(M_~s)):~w/integer", [Name, Size])]; +gen_encoder_bin(#field{name = Name, len = Size, type = Type}) -> + [io_lib:format("M_~s:~w/~s", [Name, Size, Type])]. +%% gen_encoder_bin(#field{name = Name, len = Size}) -> +%% [io_lib:format("M_~s:~w", [Name, Size])]. indent(Atom, Extra) when is_atom(Atom) -> indent(atom_to_list(Atom), Extra); @@ -459,14 +788,19 @@ indent(List, Extra) -> s2a(Name) when is_atom(Name) -> Name; s2a(Name) -> - lists:map(fun(32) -> $_; - ($/) -> $_; - ($-) -> $_; - ($.) -> $_; - ($,) -> $_; - (C) -> C - end, - string:to_lower(Name)). + S = lists:map(fun(32) -> $_; + ($/) -> $_; + ($-) -> $_; + ($.) -> $_; + ($,) -> $_; + (C) -> C + end, + string:to_lower(Name)), + list_to_atom(S). + +to_string(S) when is_list(S) -> S; +to_string(A) when is_atom(A) -> atom_to_list(A); +to_string(B) when is_binary(B) -> binary_to_list(B). append([], Acc) -> Acc; @@ -489,8 +823,8 @@ collect(Fun, Fields) -> collect(Fun, Fields, []). gen_enum(Name, Value, Cnt, Next, {FwdFuns, RevFuns}) -> - Fwd = io_lib:format("enum_v2_~s(~s) -> ~w", [s2a(Name), s2a(Value), Cnt]), - Rev = io_lib:format("enum_v2_~s(~w) -> ~s", [s2a(Name), Cnt, s2a(Value)]), + Fwd = io_lib:format("enum_v2_~s(~p) -> ~w", [Name, s2a(Value), Cnt]), + Rev = io_lib:format("enum_v2_~s(~w) -> ~p", [Name, Cnt, s2a(Value)]), gen_enum(Name, Next, Cnt + 1, {[Fwd|FwdFuns], [Rev|RevFuns]}). gen_enum(_, [], _, {FwdFuns, RevFuns}) -> @@ -510,25 +844,34 @@ gen_message_type([], {FwdFuns, RevFuns}) -> gen_message_type([{Value, Name}|Rest], Acc) -> gen_message_type(Value, Name, Rest, Acc). +reorder_flags([]) -> []; +reorder_flags(Flags) -> + {Head, Tail} = lists:split(8, Flags), + lists:reverse(Head) ++ reorder_flags(Tail). + build_late_assign([]) -> []; -build_late_assign([H = {_Name, _Len, {array, _Multi}} | T]) -> +build_late_assign([H = #field{type = array} | T]) -> build_late_assign(H, T); build_late_assign([_ | T]) -> build_late_assign(T). -build_late_assign({Name, Len, {array, Multi}}, T) +build_late_assign(#field{name = Name, len = Len, type = array, spec = Multi}, T) when is_list(Multi) -> - Init = io_lib:format("M_~s_size = M_~s * ~w", [s2a(Name), s2a(Multi), Len]), + Init = io_lib:format("M_~s_size = M_~s * ~w", [Name, s2a(Multi), Len]), + build_late_assign(Name, Init, T); +build_late_assign(#field{name = Name, type = array, spec = {Size, Type}}, T) + when Type =:= integer; Type =:= bits -> + Init = io_lib:format("M_~s_size = M_~s_len * ~w", [Name, Name, Size]), build_late_assign(Name, Init, T); -build_late_assign({Name, _Len, {array, Multi}}, T) -> - Init = io_lib:format("M_~s_size = M_~s_len * ~w", [s2a(Name), s2a(Name), Multi]), +build_late_assign(#field{name = Name, type = array, spec = {Size, _}}, T) -> + Init = io_lib:format("M_~s_size = M_~s_len * ~w * 8", [Name, Name, Size]), build_late_assign(Name, Init, T). build_late_assign(Name, Init, Fields) -> - Match = io_lib:format("M_~s:M_~s_size/bytes", [s2a(Name), s2a(Name)]), + Match = io_lib:format("M_~s:M_~s_size/bits", [Name, Name]), {Body, Next} = collect_late_assign(Fields, [Match]), - M = io_lib:format(" <<~s>> = M_~s_Rest,", [string:join(Body, ",\n "), s2a(Name)]), + M = io_lib:format(" <<~s>> = M_~s_Rest,", [string:join(Body, ",\n "), Name]), [" ", Init, ",\n", M, "\n"] ++ build_late_assign(Next). collect_late_assign([], Acc) -> @@ -542,16 +885,15 @@ collect_late_assign(Fields = [H | T], Acc) -> end. -collect_enum({Name, _, {enum, Enum}}, Acc) -> +collect_enum(#field{name = Name, type = enum, spec = Enum}, Acc) -> {FwdFuns, RevFuns} = gen_enum(Name, Enum, 0, {[], []}), - Wildcard = io_lib:format("enum_v2_~s(X) when is_integer(X) -> X", [s2a(Name)]), + Wildcard = io_lib:format("enum_v2_~s(X) when is_integer(X) -> X", [Name]), S = string:join(FwdFuns ++ RevFuns ++ [Wildcard], ";\n") ++ ".\n", lists:keystore(Name, 1, Acc, {Name, S}); collect_enum(_, Acc) -> Acc. -collect_enums({_, _, Fields}, AccIn) - when is_list(Fields) -> +collect_enums(#ie{type = undefined, fields = Fields}, AccIn) -> lists:foldr(fun(X, Acc) -> collect_enum(X, Acc) end, AccIn, Fields); collect_enums(_, AccIn) -> AccIn. @@ -561,49 +903,78 @@ write_enums(IEs) -> {_, Str} = lists:unzip(E), string:join(Str, "\n"). -write_record({_Id, Name, Fields}) - when is_list(Fields) -> +write_record(#ie{name = Name, type = undefined, fields = Fields}) -> Indent = "\t ", - RecordDef = string:join(collect(fun gen_record_def/1, [{"Instance", 0, integer} | Fields], []), [",\n", Indent]), - io_lib:format("-record(~s, {~n~s~s~n}).~n", [s2a(Name), Indent, RecordDef]); + RecordDef = string:join(collect(fun gen_record_def/1, [?'Instance' | Fields], []), [",\n", Indent]), + io_lib:format("-record(~s, {~n~s~s~n}).~n", [Name, Indent, RecordDef]); write_record(_) -> []. -write_decoder(FunName, {Id, Name, Fields}) - when is_list(Fields) -> - MatchIdent = indent(FunName, 3), +write_decoder(#ie{min_field_count = Min, fields = Fields} = IE, Fns) + when is_integer(Min), length(Fields) > Min -> + SubIE = IE#ie{min_field_count = undefined}, + lists:foldl( + fun (Len, FnsSub) -> + {H,T} = lists:split(Len, Fields), + case T of + [] -> FnsSub; + _ -> + write_decoder(SubIE#ie{fields = H ++ [?WildCard]}, FnsSub) + end + end, Fns, lists:seq(Min, length(Fields))); + +write_decoder(#ie{id = Id, type = undefined, name = Name, fields = Fields}, Fns) -> + MatchIdent = indent(?DecoderFunName, 3), Match = string:join(collect(fun gen_decoder_header_match/1, Fields), [",\n", MatchIdent]), Body = build_late_assign(Fields), RecIdent = indent(Name, 6), RecAssign = string:join(["instance = Instance" | collect(fun gen_decoder_record_assign/1, Fields)], [",\n", RecIdent]), - io_lib:format("~s(<<~s>>, ~w, Instance) ->~n~s #~s{~s}", - [FunName, Match, Id, Body, s2a(Name), RecAssign]); - -write_decoder(FunName, {Id, _Name, Helper}) - when is_atom(Helper) -> - io_lib:format("~s(<>, ~w, Instance) ->~n decode_~s(Data, Instance)", - [FunName, Id, Helper]). - -write_encoder(FunName, {Id, Name, Fields}) - when is_list(Fields) -> + F = io_lib:format("~s(<<~s>>, ~w, Instance) ->~n~s #~s{~s}", + [?DecoderFunName, Match, Id, Body, Name, RecAssign]), + [F | Fns]; + +write_decoder(#ie{id = Id, type = Helper}, Fns) -> + F = io_lib:format("~s(<>, ~w, Instance) ->~n decode_~s(Data, Instance)", + [?DecoderFunName, Id, Helper]), + [F | Fns]. + +write_encoder(#ie{min_field_count = Min, fields = Fields} = IE, Fns) + when is_integer(Min), length(Fields) > Min -> + SubIE = IE#ie{min_field_count = undefined}, + lists:foldl( + fun (Len, FnsSub) -> + {H,T} = lists:split(Len, Fields), + case T of + [] -> + write_encoder(SubIE#ie{fields = H}, FnsSub); + [#field{type = '_'}|_] -> FnsSub; + [M|_] -> + write_encoder(SubIE#ie{fields = H ++ [M#field{type = undefined}]}, FnsSub) + end + end, Fns, lists:seq(length(Fields), Min, -1)); + +write_encoder(#ie{id = Id, name = Name, type = undefined, fields = Fields}, Fns) -> RecIdent = indent("encode_v2_element(#", 2), RecAssign = string:join(["instance = Instance" | collect(fun gen_encoder_record_assign/1, Fields)], [",\n", RecIdent]), - FunHead = io_lib:format("encode_v2_element(#~s{~n~s~s}) ->~n", [s2a(Name), RecIdent, RecAssign]), - DecHead = io_lib:format(" ~s(~w, Instance, ", [FunName, Id]), + FunHead = io_lib:format("encode_v2_element(#~s{~n~s~s}) ->~n", [Name, RecIdent, RecAssign]), + DecHead = io_lib:format(" ~s(~w, Instance, ", [?EncoderFunName, Id]), BinIndent = indent(DecHead, 2), BinAssign = string:join(collect(fun gen_encoder_bin/1, Fields), [",\n", BinIndent]), - io_lib:format("~s~s<<~s>>)", [FunHead, DecHead, BinAssign]); -write_encoder(FunName, {Id, Name, Helper}) - when is_atom(Helper) -> - io_lib:format("encode_v2_element(#~s{instance = Instance} = IE) ->~n ~s(~w, Instance, encode_~s(IE))", - [s2a(Name), FunName, Id, Helper]). + F = io_lib:format("~s~s<<~s>>)", [FunHead, DecHead, BinAssign]), + [F | Fns]; +write_encoder(#ie{id = Id, name = Name, type = Helper}, Fns) -> + F = io_lib:format("encode_v2_element(#~s{instance = Instance} = IE) ->~n ~s(~w, Instance, encode_~s(IE))", + [Name, ?EncoderFunName, Id, Helper]), + [F | Fns]. -write_pretty_print(_, Def) -> - io_lib:format("?PRETTY_PRINT(pretty_print_v2, ~s)", [s2a(element(2, Def))]). +write_pretty_print(_, #ie{name = Name}) -> + io_lib:format("?PRETTY_PRINT(pretty_print_v2, ~s)", [Name]). main(_) -> + IEs = ies(), + MsgDescription = string:join([io_lib:format("msg_description_v2(~s) -> <<\"~s\">>", [s2a(X), X]) || {_, X} <- msgs()] ++ ["msg_description_v2(X) -> io_lib:format(\"~p\", [X])"], ";\n") ++ ".\n", @@ -611,21 +982,21 @@ main(_) -> ErrorFun = ["message_type_v2(Type) -> error(badarg, [Type])"], MTypes = string:join(FwdFuns ++ RevFuns ++ ErrorFun, ";\n") ++ ".\n", - Records = string:join([write_record(X) || X <- ies()], "\n"), + Records = string:join([write_record(X) || X <- IEs], "\n"), HrlRecs = io_lib:format("~n~n~s", [Records]), - Enums = write_enums(ies()), - - CatchAnyDecoder = "decode_v2_element(Value, Tag, Instance) ->\n {Tag, Instance, Value}", + Enums = write_enums(IEs), - Funs = string:join([write_decoder("decode_v2_element", X) || X <- ies()] ++ [CatchAnyDecoder], ";\n\n"), + CatchAnyDecoder = ?DecoderFunName ++ "(Value, Tag, Instance) ->\n {Tag, Instance, Value}", + DecoderFns = lists:foldr(fun write_decoder/2, [CatchAnyDecoder], IEs), + Funs = string:join(DecoderFns, ";\n\n"), - CatchAnyEncoder = "encode_v2_element({Tag, Instance, Value}) when is_integer(Tag), is_integer(Instance), is_binary(Value) ->\n encode_v2_element(Tag, Instance, Value)", - EncFuns = string:join([write_encoder("encode_v2_element", X) || X <- ies()] - ++ [CatchAnyEncoder] , ";\n\n"), + CatchAnyEncoder = ?EncoderFunName ++ "({Tag, Instance, Value}) when is_integer(Tag), is_integer(Instance), is_binary(Value) ->\n encode_v2_element(Tag, Instance, Value)", + EncoderFns = lists:foldr(fun write_encoder/2, [CatchAnyEncoder], IEs), + EncFuns = string:join(EncoderFns, ";\n\n"), CatchAnyPretty = "pretty_print_v2(_, _) ->\n no", - RecPrettyDefs = string:join([write_pretty_print("pretty_print_v2", X) || X <- ies()] + RecPrettyDefs = string:join([write_pretty_print("pretty_print_v2", X) || X <- IEs] ++ [CatchAnyPretty] , ";\n"), ErlDecls = io_lib:format("~n~n~s~n~s~n~s~n~s.~n~n~s.~n~n~s.~n", diff --git a/rebar.config b/rebar.config index 691b225..52a8809 100644 --- a/rebar.config +++ b/rebar.config @@ -6,14 +6,15 @@ {ppp, {git, "git://github.com/travelping/ppp", {branch, "modernize"}}} ]}. -{minimum_otp_vsn, "20.1"}. +{minimum_otp_vsn, "21.3"}. {plugins, []}. {profiles, [ {test, [{deps, - [{proper, "1.2.0"}]}, - {plugins, [coveralls]} + [{proper, {git, "https://github.com/proper-testing/proper.git", + {branch, "master"}}}]}, + {plugins, [{coveralls, "2.1.0"}]} ]}, {pcap, [{deps, @@ -23,7 +24,9 @@ {branch, "master"}}}, {pcapng, {git, "git://github.com/travelping/pcapng.git", {branch, "master"}}}, - {proper, "1.2.0"}]} + {proper, {git, "https://github.com/proper-testing/proper.git", + {branch, "master"}}} + ]} ]} ]}. @@ -44,3 +47,4 @@ {do_coveralls_after_eunit, false}. {coveralls_coverdata, "_build/test/cover/ct.coverdata"}. {coveralls_service_name, "travis-ci"}. +{coveralls_parallel, true}. diff --git a/src/gtp_packet.erl b/src/gtp_packet.erl index e561350..910626e 100644 --- a/src/gtp_packet.erl +++ b/src/gtp_packet.erl @@ -14,18 +14,18 @@ decode/1, decode/2, decode_ies/1, decode_ies/2, msg_description/1, msg_description_v2/1, pretty_print/1]). --compile(export_all). --compile([{parse_transform, cut}, - bin_opt_info]). +-export([encode_v1_uli/1]). + +-compile([{parse_transform, cut}]). -compile({inline,[decode_tbcd/1, decode_fqdn/1, decode_v2_grouped/1]}). + -include("gtp_packet.hrl"). --define(V2_INDICATION_FLAGS, ['DAF', 'DTF', 'HI', 'DFI', 'OI', 'ISRSI', 'ISRAI', 'SGWCI', - 'SQCI', 'UIMSI', 'CFSI', 'CRSI', 'P', 'PT', 'SI', 'MSV', - 'RetLoc', 'PBIC', 'SRNI', 'S6AF', 'S4AF', 'MBMDT', 'ISRAU', 'CCRSI', - 'CPRAI', 'ARRL', 'PPOF', 'PPON/PPEI', 'PPSI', 'CSFBI', 'CLII', 'CPSR', - 'Spare', 'Spare', 'Spare', 'Spare', 'PSCI', 'PCRI', 'AOSI', 'AOPI']). +-ifdef(TEST). +-compile([bin_opt_info]). +-compile([export_all, nowarn_export_all]). +-endif. %%==================================================================== %% API @@ -47,15 +47,17 @@ decode_ies(#gtp{ie = IEs} = Msg, #{ies := map}) decode_ies(#gtp{ie = IEs} = Msg, #{ies := Format} = Opts) when not is_binary(IEs) orelse (Format /= map andalso Format /= binary) -> error(badargs, [Msg, Opts]); -decode_ies(#gtp{version = Version, type = Type, ie = IEs} = Msg, #{ies := map}) +decode_ies(#gtp{type = g_pdu} = Msg, _) -> + Msg; +decode_ies(#gtp{version = Version, ie = IEs} = Msg, #{ies := map}) when Version =:= v1; Version =:= prime_v0; Version =:= prime_v0s; Version =:= prime_v1; Version =:= prime_v2 -> - Msg#gtp{ie = decode_v1(Type, IEs)}; + Msg#gtp{ie = decode_v1(IEs, -1, 0, #{})}; decode_ies(#gtp{version = v2, ie = IEs} = Msg, #{ies := map}) -> - Msg#gtp{ie = decode_v2(IEs)}; + Msg#gtp{ie = decode_v2(IEs, #{})}; decode_ies(Msg, _) -> Msg. @@ -185,16 +187,15 @@ pad_length(Width, Length) -> %% pad binary to specific length %% -> http://www.erlang.org/pipermail/erlang-questions/2008-December/040709.html %% -pad_to(Width, Binary) -> - case pad_length(Width, size(Binary)) of - 0 -> Binary; - N -> <> - end. +%% pad_to(Width, Binary) -> +%% case pad_length(Width, size(Binary)) of +%% 0 -> Binary; +%% N -> <> +%% end. put_ie(IE, IEs) -> Key = {element(1, IE), element(2, IE)}, UpdateFun = fun(V) when is_list(V) -> [IE | V]; - (undefined) -> IE; (V) -> [IE, V] end, maps:update_with(Key, UpdateFun, IE, IEs). @@ -202,11 +203,59 @@ put_ie(IE, IEs) -> bool2int(false) -> 0; bool2int(true) -> 1. +int2bool(0) -> false; +int2bool(_) -> true. + encode_flag(Flag, Flags) -> bool2int(proplists:get_bool(Flag, Flags)). is_bin(Bin) -> bool2int(is_binary(Bin)). +%% decoder funs for optional fields +maybe(Bin, 0, _Fun, IE) -> + {IE, Bin}; +maybe(Bin, 1, Fun, IE) -> + Fun(Bin, IE). + +bin(Bin, Len, Pos, IE) -> + <> = Bin, + {setelement(Pos, IE, V), Rest}. + +int(Bin, Len, Pos, IE) -> + <> = Bin, + {setelement(Pos, IE, V), Rest}. + +plmn(<>, Pos, IE) -> + V = {decode_mcc(MCCMNC), decode_mnc(MCCMNC)}, + {setelement(Pos, IE, V), Rest}. + +spare(Bin, Len, IE) -> + <<_:Len, Rest/binary>> = Bin, + {IE, Rest}. + +length_bin(Bin, LenSize, Pos, IE) -> + <> = Bin, + bin(Rest, Len, Pos, IE). + +%% encoder funs for optional fields +maybe(true, Fun, IE) -> Fun(IE); +maybe(_, _, IE) -> IE. + +int(Int, Size, IE) -> + <>. + +bin(Bin, Size, IE) -> + <>. + +plmn({MCC, MNC}, IE) -> + <>. + +%% spare(Len, IE) -> +%% <>. + +length_bin(Bin, LenSize, IE) -> + <>. + maybe_bin(<>, 0, _, _, IE) -> {IE, Bin}; maybe_bin(<>, 1, Len, Pos, IE) -> @@ -275,20 +324,31 @@ decode_tbcd(<<15:4, Lo:4, _/binary>>, BCD) -> decode_tbcd(<>, BCD) -> decode_tbcd(Next, <>). -decode_v1_rai(<>, Instance) -> +decode_mcc(<>) -> + decode_tbcd(<>). + +decode_mnc(<<_:8, MNC3:4, _:4, MNCHi:8>>) -> + decode_tbcd(<>). + +encode_mccmnc(MCC, MNC) -> + [MCC1, MCC2, MCC3 | _] = [ string_to_tbcd(X) || <> <= MCC] ++ [15,15,15], + [MNC1, MNC2, MNC3 | _] = [ string_to_tbcd(X) || <> <= MNC] ++ [15,15,15], + <>. + +decode_v1_rai(<>, Instance) -> #routeing_area_identity{ instance = Instance, - mcc = decode_tbcd(<>), - mnc = decode_tbcd(<>), + mcc = decode_mcc(MCCMNC), + mnc = decode_mnc(MCCMNC), lac = LAC, rac = RAC}. -decode_v1_uli(<>, Instance) -> +decode_v1_uli(<>, Instance) -> ULI = #user_location_information{ instance = Instance, type = Type, - mcc = decode_tbcd(<>), - mnc = decode_tbcd(<>), + mcc = decode_mcc(MCCMNC), + mnc = decode_mnc(MCCMNC), lac = LAC }, case Type of @@ -343,31 +403,32 @@ decode_data_record_packet(< - %% G-PDU - Data; -decode_v1(_, Data) -> - decode_v1(Data, -1, 0, #{ {recovery, 0} => undefined }). - v1_instance(CurrId, PrevId, PrevInst) when CurrId == PrevId -> PrevInst + 1; v1_instance(_CurrId, _PrevId, _PrevInst) -> 0. -decode_v2_indication_flags(<<>>, _, Acc) -> - Acc; -decode_v2_indication_flags(<<0:1, Next/bitstring>>, [_ | Flags], Acc) -> - decode_v2_indication_flags(Next, Flags, Acc); -decode_v2_indication_flags(<<1:1, Next/bitstring>>, [F | Flags], Acc) -> - decode_v2_indication_flags(Next, Flags, [F | Acc]). - -decode_v2_indication_flags(<>) -> - decode_v2_indication_flags(Flags, ?V2_INDICATION_FLAGS, []); -decode_v2_indication_flags(Flags) -> - decode_v2_indication_flags(Flags, ?V2_INDICATION_FLAGS, []). - -decode_v2_user_location_information(<<_:2, FlagLAI:1, FlagECGI:1, +decode_flags(0, _) -> + []; +decode_flags(Int, []) -> + [Int]; +decode_flags(Int, ['_' | Flags]) -> + decode_flags(Int div 2, Flags); +decode_flags(Int, [F | Flags]) when Int rem 2 /= 0 -> + [F | decode_flags(Int div 2, Flags)]; +decode_flags(Int, [_ | Flags]) -> + decode_flags(Int div 2, Flags). + +encode_flags([I|_], []) when is_integer(I) -> I; +encode_flags([_|N], []) -> encode_flags(N, []); +encode_flags([], _) -> 0; +encode_flags(Flags, ['_' | N]) -> encode_flags(Flags, N) * 2; +encode_flags(Flags, [F | N]) -> + bool2int(lists:member(F, Flags)) + + encode_flags(Flags -- [F], N) * 2. + +decode_v2_user_location_information(<>, Instance) -> IE0 = #v2_user_location_information{instance = Instance}, @@ -376,8 +437,12 @@ decode_v2_user_location_information(<<_:2, FlagLAI:1, FlagECGI:1, {IE3, Rest3} = maybe_bin(Rest2, FlagRAI, 7, #v2_user_location_information.rai, IE2), {IE4, Rest4} = maybe_bin(Rest3, FlagTAI, 5, #v2_user_location_information.tai, IE3), {IE5, Rest5} = maybe_bin(Rest4, FlagECGI, 7, #v2_user_location_information.ecgi, IE4), - {IE6, _} = maybe_bin(Rest5, FlagLAI, 5, #v2_user_location_information.lai, IE5), - IE6. + {IE6, Rest6} = maybe_bin(Rest5, FlagLAI, 5, #v2_user_location_information.lai, IE5), + {IE7, Rest7} = + maybe_bin(Rest6, FlagEeNB, 6, #v2_user_location_information.macro_enb, IE6), + {IE8, _Rest} = + maybe_bin(Rest7, FlagEMeNB, 6, #v2_user_location_information.ext_macro_enb, IE7), + IE8. decode_v2_fully_qualified_tunnel_endpoint_identifier(<>, Instance) -> @@ -389,15 +454,84 @@ decode_v2_fully_qualified_tunnel_endpoint_identifier(<>, Instance) -> - #v2_serving_network{ +decode_v2_fully_qualified_pdn_connection_set_identifier(<>, Instance) -> + CSIDLen = NoOfCSIDS * 2, + IE0 = #v2_fully_qualified_pdn_connection_set_identifier{ + instance = Instance, + node_id_type = NodeIdType}, + {NodeId, <>} = + case {NodeIdType, Rest0} of + {0, <>} -> + {NodeId0, Rest1}; + {1, <>} -> + {NodeId0, Rest1}; + {2, <>} -> + {{MCCMNC div 1000, MCCMNC rem 1000, NodeId0}, Rest1} + end, + IE0#v2_fully_qualified_pdn_connection_set_identifier{ + node_id = NodeId, + csids = [CSID || <> <= CSIDs] + }. + +decode_v2_private_extension(<>, Instance) -> + decode_v2_private_extension(Value, EnterpriseId, Instance). + +decode_v2_private_extension(Value, EnterpriseId, Instance) -> + #v2_private_extension{ instance = Instance, - mcc = decode_tbcd(<>), - mnc = decode_tbcd(<>) + enterprise_id = EnterpriseId, + value = Value }. -decode_v2(Data) -> - decode_v2(Data, #{ {v2_recovery, 0} => undefined }). +decode_v2_twan_identifier(<<_:3, FlagLAII:1, FlagOPNAI:1, FlagPLMNI:1, + FlagCIVAI:1, FlagBSSIDI:1, SSIDLen:8, + Rest0/binary>>, Instance) -> + IE0 = #v2_twan_identifier{instance = Instance}, + {IE1, Rest1} = bin(Rest0, SSIDLen, #v2_twan_identifier.ssid, IE0), + {IE2, Rest2} = maybe(Rest1, FlagBSSIDI, bin(_, 6, #v2_twan_identifier.bssid, _), IE1), + {IE3, Rest3} = maybe(Rest2, FlagCIVAI, length_bin(_, 8, #v2_twan_identifier.civic_address, _), IE2), + {IE4, Rest4} = maybe(Rest3, FlagPLMNI, plmn(_, #v2_twan_identifier.plmn_id, _), IE3), + {IE5, Rest5} = maybe(Rest4, FlagOPNAI, length_bin(_, 8, #v2_twan_identifier.operator_name, _), IE4), + {IE6, Rest6} = maybe(Rest5, FlagLAII, int(_, 8, #v2_twan_identifier.relay_identity_type, _), IE5), + {IE7, Rest7} = maybe(Rest6, FlagLAII, length_bin(_, 8, #v2_twan_identifier.relay_identity, _), IE6), + {IE8, _Rest} = maybe(Rest7, FlagLAII, length_bin(_, 8, #v2_twan_identifier.circuit_id, _), IE7), + IE8. + +decode_v2_paging_and_service_information(<<_:4, EBI:4, _:7, FlagPPI:1, Rest0/binary>>, + Instance) -> + IE0 = #v2_paging_and_service_information{instance = Instance, ebi = EBI}, + {IE1, Rest1} = maybe(Rest0, FlagPPI, spare(_, 2, _), IE0), + {IE2, _Rest} = maybe(Rest1, FlagPPI, int(_, 6, #v2_paging_and_service_information.ppi, _), IE1), + IE2. + +decode_v2_integer_number(Bin, Instance) -> + #v2_integer_number{ + instance = Instance, width = byte_size(Bin), + value = binary:decode_unsigned(Bin)}. + +decode_v2_remote_user_id(<<_:6, FlagIMEI:1, FlagMSISDN:1, IMSILen:8, + Rest0/binary>>, Instance) -> + IE0 = #v2_remote_user_id{instance = Instance}, + {IE1, Rest1} = bin(Rest0, IMSILen, #v2_remote_user_id.imsi, IE0), + {IE2, Rest2} = maybe(Rest1, FlagMSISDN, length_bin(_, 8, #v2_remote_user_id.msisdn, _), IE1), + {IE3, _Rest} = maybe(Rest2, FlagIMEI, length_bin(_, 8, #v2_remote_user_id.imei, _), IE2), + IE3. + +decode_v2_maximum_packet_loss_rate(<<_:6, FlagDL:1, FlagUL:1, Rest0/binary>>, Instance) -> + IE0 = #v2_maximum_packet_loss_rate{instance = Instance}, + {IE1, Rest1} = maybe(Rest0, FlagUL, int(_, 16, #v2_maximum_packet_loss_rate.ul, _), IE0), + {IE2, _Rest} = maybe(Rest1, FlagDL, int(_, 16, #v2_maximum_packet_loss_rate.dl, _), IE1), + IE2. + +decode_v2_monitoring_event_extension_information(<<_:7, FlagLRTP:1, RefId:32, IdLen:8, + Rest0/binary>>, Instance) -> + IE0 = #v2_monitoring_event_extension_information{ + instance = Instance, scef_reference_id = RefId}, + {IE1, Rest1} = bin(Rest0, IdLen, #v2_monitoring_event_extension_information.scef_id, IE0), + {IE2, _Rest} = maybe(Rest1, FlagLRTP, int(_, 32, #v2_monitoring_event_extension_information.remaining_minimum_lrtp, _), IE1), + IE2. decode_v2(<<>>, IEs) -> IEs; @@ -535,9 +669,7 @@ encode_v1_rai(#routeing_area_identity{ mnc = MNC, lac = LAC, rac = RAC}) -> - [MCC1, MCC2, MCC3 | _] = [ string_to_tbcd(X) || <> <= MCC] ++ [15,15,15], - [MNC1, MNC2, MNC3 | _] = [ string_to_tbcd(X) || <> <= MNC] ++ [15,15,15], - <>. + <<(encode_mccmnc(MCC, MNC))/binary, LAC:16, RAC:8>>. encode_v1_uli(#user_location_information{ @@ -548,15 +680,13 @@ encode_v1_uli(#user_location_information{ ci = CI, sac = SAC, rac = RAC}) -> - [MCC1, MCC2, MCC3 | _] = [ string_to_tbcd(X) || <> <= MCC] ++ [15,15,15], - [MNC1, MNC2, MNC3 | _] = [ string_to_tbcd(X) || <> <= MNC] ++ [15,15,15], Info = case Type of 0 -> CI; 1 -> SAC; 2 -> (RAC bsl 8) bor 255; _ -> 16#ffff end, - <>. + <>. encode_fqdn(FQDN) -> << <<(size(Part)):8, Part/binary>> || Part <- FQDN >>. @@ -596,14 +726,12 @@ encode_data_record_packet(#data_record_packet{ BinRecs = << <<(size(R)):16, R/binary>> || R <- Records >>, << (length(Records)):8, Format:8, App:4, Release:4, (Version + 1):8, BinRecs/binary >>. -encode_v2_indication_flags(Flags) -> - pad_to(5, << <<(bool2int(lists:member(F, Flags))):1>> || F <- ?V2_INDICATION_FLAGS>>). - encode_v2_user_location_information( #v2_user_location_information{cgi = CGI, sai = SAI, rai = RAI, - tai = TAI, ecgi = ECGI, lai = LAI}) -> + tai = TAI, ecgi = ECGI, lai = LAI, + macro_enb = MeNB, ext_macro_enb = EMeNB}) -> - IE0 = <<0:2, + IE0 = <<(is_bin(EMeNB)):1, (is_bin(MeNB)):1, (is_bin(LAI)):1, (is_bin(ECGI)):1, (is_bin(TAI)):1, (is_bin(RAI)):1, (is_bin(SAI)):1, (is_bin(CGI)):1>>, @@ -612,7 +740,9 @@ encode_v2_user_location_information( IE3 = maybe_bin(RAI, IE2), IE4 = maybe_bin(TAI, IE3), IE5 = maybe_bin(ECGI, IE4), - maybe_bin(LAI, IE5). + IE6 = maybe_bin(LAI, IE5), + IE7 = maybe_bin(MeNB, IE6), + _IE = maybe_bin(EMeNB,IE7). encode_v2_fully_qualified_tunnel_endpoint_identifier( #v2_fully_qualified_tunnel_endpoint_identifier{ @@ -624,10 +754,89 @@ encode_v2_fully_qualified_tunnel_endpoint_identifier( IE1 = maybe_bin(IPv4, IE0), maybe_bin(IPv6, IE1). -encode_v2_mccmnc(#v2_serving_network{mcc = MCC, mnc = MNC}) -> - [MCC1, MCC2, MCC3 | _] = [ string_to_tbcd(X) || <> <= MCC] ++ [15,15,15], - [MNC1, MNC2, MNC3 | _] = [ string_to_tbcd(X) || <> <= MNC] ++ [15,15,15], - <>. +encode_v2_fully_qualified_pdn_connection_set_identifier( + #v2_fully_qualified_pdn_connection_set_identifier{ + node_id_type = NodeIdType, + node_id = NodeId, + csids = CSIDs}) -> + NoOfCSIDS = length(CSIDs), + IE0 = <>, + IE1 = case NodeIdType of + 0 -> <>; + 1 -> <>; + 2 -> {MCC, MNC, Id} = NodeId, + <> + end, + <> || CSID <- CSIDs >>/binary>>. + +encode_v2_private_extension(EnterpriseId, Value) -> + <>. + +encode_v2_private_extension( + #v2_private_extension{ + enterprise_id = EnterpriseId, + value = Value + }) -> + encode_v2_private_extension(EnterpriseId, Value). + +encode_v2_twan_identifier( + #v2_twan_identifier{ + ssid = SSID, + bssid = BSSID, + civic_address = CivicAddress, + plmn_id = MCCMNC, + operator_name = OperatorName, + relay_identity_type = RelayIdentityType, + relay_identity = RelayIdentity, + circuit_id = CircuitId}) -> + FlagLAII = is_integer(RelayIdentityType) andalso + is_binary(RelayIdentity) andalso is_binary(CircuitId), + FlagOPNAI = is_binary(OperatorName), + FlagPLMNI = is_tuple(MCCMNC), + FlagCIVAI = is_binary(CivicAddress), + FlagBSSIDI = is_binary(BSSID), + + IE0 = <<0:3, (bool2int(FlagLAII)):1, (bool2int(FlagOPNAI)):1, + (bool2int(FlagPLMNI)):1, (bool2int(FlagCIVAI)):1, + (bool2int(FlagBSSIDI)):1>>, + IE1 = length_bin(SSID, 8, IE0), + IE2 = maybe(FlagBSSIDI, bin(BSSID, 6, _), IE1), + IE3 = maybe(FlagCIVAI, length_bin(CivicAddress, 8, _), IE2), + IE4 = maybe(FlagPLMNI, plmn(MCCMNC, _), IE3), + IE5 = maybe(FlagOPNAI, length_bin(OperatorName, 8, _), IE4), + IE6 = maybe(FlagLAII, int(RelayIdentityType, 8, _), IE5), + IE7 = maybe(FlagLAII, length_bin(RelayIdentity, 8, _), IE6), + _IE = maybe(FlagLAII, length_bin(CircuitId, 8, _), IE7). + +encode_v2_paging_and_service_information( + #v2_paging_and_service_information{ebi = EBI, ppi = PPI}) -> + FlagPPI = is_integer(PPI), + IE0 = <<0:4, EBI:4, 0:7, (bool2int(FlagPPI))>>, + _IE = maybe(FlagPPI, int(PPI band 16#3f, 8, _), IE0). + +encode_v2_integer_number(#v2_integer_number{width = W, value = I}) -> + <>. + +encode_v2_remote_user_id(#v2_remote_user_id{imsi = IMSI, msisdn = MSISDN, imei = IMEI}) -> + IE0 = <<0:6, (is_bin(IMEI)):1, (is_bin(MSISDN)):1>>, + IE1 = length_bin(IMSI, 8, IE0), + IE2 = maybe(is_binary(MSISDN), length_bin(MSISDN, 8, _), IE1), + _IE = maybe(is_binary(IMSI), length_bin(IMSI, 8, _), IE2). + +encode_v2_maximum_packet_loss_rate(#v2_maximum_packet_loss_rate{ul = UL, dl = DL}) -> + FlagUL = is_integer(UL), + FlagDL = is_integer(DL), + IE0 = <<0:6, (bool2int(FlagDL)):1, (bool2int(FlagUL)):1>>, + IE1 = maybe(FlagUL, int(UL, 16, _), IE0), + _IE = maybe(FlagDL, int(DL, 16, _), IE1). + +encode_v2_monitoring_event_extension_information( + #v2_monitoring_event_extension_information{ + scef_reference_id = RefId, scef_id = ScefId, remaining_minimum_lrtp = RemMinLRTP}) -> + FlagLRTP = is_integer(RemMinLRTP), + IE0 = <<0:7, (bool2int(FlagLRTP)):1, RefId:32>>, + IE1 = length_bin(ScefId, 8, IE0), + _IE = maybe(FlagLRTP, int(RemMinLRTP, 32, _), IE1). %% -include("gtp_packet_v1_gen.hrl"). @@ -2776,10 +2985,12 @@ enum_v2_type(ipv4) -> 1; enum_v2_type(ipv6) -> 2; enum_v2_type(ipv4v6) -> 3; enum_v2_type(non_ip) -> 4; +enum_v2_type(ethernet) -> 5; enum_v2_type(1) -> ipv4; enum_v2_type(2) -> ipv6; enum_v2_type(3) -> ipv4v6; enum_v2_type(4) -> non_ip; +enum_v2_type(5) -> ethernet; enum_v2_type(X) when is_integer(X) -> X. enum_v2_v2_cause(reserved) -> 1; @@ -2853,6 +3064,15 @@ enum_v2_v2_cause(multiple_pdn_connections_for_a_given_apn_not_allowed) -> 116; enum_v2_v2_cause(target_access_restricted_for_the_subscriber) -> 117; enum_v2_v2_cause(mme_sgsn_refuses_due_to_vplmn_policy) -> 119; enum_v2_v2_cause(gtp_c_entity_congestion) -> 120; +enum_v2_v2_cause(late_overlapping_request) -> 121; +enum_v2_v2_cause(timed_out_request) -> 122; +enum_v2_v2_cause(ue_is_temporarily_not_reachable_due_to_power_saving) -> 123; +enum_v2_v2_cause(relocation_failure_due_to_nas_message_redirection) -> 124; +enum_v2_v2_cause(ue_not_authorised_by_ocs_or_external_aaa_server) -> 125; +enum_v2_v2_cause(multiple_accesses_to_a_pdn_connection_not_allowed) -> 126; +enum_v2_v2_cause(request_rejected_due_to_ue_capability) -> 127; +enum_v2_v2_cause(s1_u_path_failure) -> 128; +enum_v2_v2_cause('5gc_not_allowed') -> 129; enum_v2_v2_cause(1) -> reserved; enum_v2_v2_cause(2) -> local_detach; enum_v2_v2_cause(3) -> complete_detach; @@ -2924,12 +3144,35 @@ enum_v2_v2_cause(116) -> multiple_pdn_connections_for_a_given_apn_not_allowed; enum_v2_v2_cause(117) -> target_access_restricted_for_the_subscriber; enum_v2_v2_cause(119) -> mme_sgsn_refuses_due_to_vplmn_policy; enum_v2_v2_cause(120) -> gtp_c_entity_congestion; +enum_v2_v2_cause(121) -> late_overlapping_request; +enum_v2_v2_cause(122) -> timed_out_request; +enum_v2_v2_cause(123) -> ue_is_temporarily_not_reachable_due_to_power_saving; +enum_v2_v2_cause(124) -> relocation_failure_due_to_nas_message_redirection; +enum_v2_v2_cause(125) -> ue_not_authorised_by_ocs_or_external_aaa_server; +enum_v2_v2_cause(126) -> multiple_accesses_to_a_pdn_connection_not_allowed; +enum_v2_v2_cause(127) -> request_rejected_due_to_ue_capability; +enum_v2_v2_cause(128) -> s1_u_path_failure; +enum_v2_v2_cause(129) -> '5gc_not_allowed'; enum_v2_v2_cause(X) when is_integer(X) -> X. decode_v2_element(<>, 1, Instance) -> #v2_international_mobile_subscriber_identity{instance = Instance, imsi = decode_tbcd(M_imsi)}; +decode_v2_element(<>, 2, Instance) -> + #v2_cause{instance = Instance, + v2_cause = enum_v2_v2_cause(M_v2_cause), + pce = M_pce, + bce = M_bce, + cs = M_cs, + offending_ie = M_offending_ie}; + decode_v2_element(<>, 71, Instance) -> apn = decode_fqdn(M_apn)}; decode_v2_element(<>, 72, Instance) -> + M_downlink:32/integer>>, 72, Instance) -> #v2_aggregate_maximum_bit_rate{instance = Instance, uplink = M_uplink, downlink = M_downlink}; @@ -2981,7 +3223,50 @@ decode_v2_element(<>, 76, Instance) -> decode_v2_element(<>, 77, Instance) -> #v2_indication{instance = Instance, - flags = decode_v2_indication_flags(M_flags)}; + flags = decode_flags(binary:decode_unsigned(M_flags, little), ['SGWCI', + 'ISRAI', + 'ISRSI','OI', + 'DFI','HI', + 'DTF','DAF', + 'MSV','SI', + 'PT','P', + 'CRSI','CFSI', + 'UIMSI','SQCI', + 'CCRSI', + 'ISRAU', + 'MBMDT','S4AF', + 'S6AF','SRNI', + 'PBIC', + 'RetLoc', + 'CPSR','CLII', + 'CSFBI','PPSI', + 'PPON/PPEI', + 'PPOF','ARRL', + 'CPRAI','AOPI', + 'AOSI','PCRI', + 'PSCI','BDWI', + 'DTCI','UASI', + 'NSI','WPMSI', + 'UNACCSI', + 'PNSI','S11TF', + 'PMTSMI', + 'CPOPCI', + 'EPCOSI', + 'ROAAI', + 'TSPCMI', + 'ENBCRSI', + 'LTEMPI', + 'LTEMUI', + 'EEVRSI', + '5GSIWK', + 'REPREFI', + '5GSNN26', + 'ETHPDN', + '5SRHOI', + '5GCNRI', + '5GCNRS', + 'N5GNMI','_', + '_','_'])}; decode_v2_element(<>, 78, Instance) -> #v2_protocol_configuration_options{instance = Instance, @@ -3015,22 +3300,37 @@ decode_v2_element(<<_:1, guaranteed_bit_rate_for_uplink = M_guaranteed_bit_rate_for_uplink, guaranteed_bit_rate_for_downlink = M_guaranteed_bit_rate_for_downlink}; -decode_v2_element(<<>>, 81, Instance) -> - #v2_flow_quality_of_service{instance = Instance}; +decode_v2_element(<>, 81, Instance) -> + #v2_flow_quality_of_service{instance = Instance, + label = M_label, + maximum_bit_rate_for_uplink = M_maximum_bit_rate_for_uplink, + maximum_bit_rate_for_downlink = M_maximum_bit_rate_for_downlink, + guaranteed_bit_rate_for_uplink = M_guaranteed_bit_rate_for_uplink, + guaranteed_bit_rate_for_downlink = M_guaranteed_bit_rate_for_downlink}; decode_v2_element(<>, 82, Instance) -> #v2_rat_type{instance = Instance, rat_type = M_rat_type}; -decode_v2_element(<>, 83, Instance) -> - decode_v2_mccmnc(Data, Instance); +decode_v2_element(<>, 83, Instance) -> + #v2_serving_network{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc)}; -decode_v2_element(<<>>, 84, Instance) -> - #v2_eps_bearer_level_traffic_flow_template{instance = Instance}; +decode_v2_element(<>, 84, Instance) -> + #v2_eps_bearer_level_traffic_flow_template{instance = Instance, + value = M_value}; -decode_v2_element(<<>>, 85, Instance) -> - #v2_traffic_aggregation_description{instance = Instance}; +decode_v2_element(<>, 85, Instance) -> + #v2_traffic_aggregation_description{instance = Instance, + value = M_value}; decode_v2_element(<>, 86, Instance) -> decode_v2_user_location_information(Data, Instance); @@ -3038,38 +3338,75 @@ decode_v2_element(<>, 86, Instance) -> decode_v2_element(<>, 87, Instance) -> decode_v2_fully_qualified_tunnel_endpoint_identifier(Data, Instance); -decode_v2_element(<<>>, 88, Instance) -> - #v2_tmsi{instance = Instance}; - -decode_v2_element(<<>>, 89, Instance) -> - #v2_global_cn_id{instance = Instance}; - -decode_v2_element(<<>>, 90, Instance) -> - #v2_s103_pdn_data_forwarding_info{instance = Instance}; - -decode_v2_element(<<>>, 91, Instance) -> - #v2_s1_u_data_forwarding_info{instance = Instance}; - -decode_v2_element(<<>>, 92, Instance) -> - #v2_delay_value{instance = Instance}; +decode_v2_element(<>, 88, Instance) -> + #v2_tmsi{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 89, Instance) -> + #v2_global_cn_id{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + value = M_value}; + +decode_v2_element(<>, 90, Instance) -> + M_eps_bearer_id_size = M_eps_bearer_id_len * 8, + <> = M_eps_bearer_id_Rest, + #v2_s103_pdn_data_forwarding_info{instance = Instance, + hsgw_address = M_hsgw_address, + gre_key = M_gre_key, + eps_bearer_id = [X || <> <= M_eps_bearer_id]}; + +decode_v2_element(<>, 91, Instance) -> + #v2_s1_u_data_forwarding_info{instance = Instance, + service_gw_address = M_service_gw_address, + teid = M_teid}; + +decode_v2_element(<>, 92, Instance) -> + #v2_delay_value{instance = Instance, + delay = M_delay}; decode_v2_element(<>, 93, Instance) -> #v2_bearer_context{instance = Instance, group = decode_v2_grouped(M_group)}; -decode_v2_element(<>, 94, Instance) -> +decode_v2_element(<>, 94, Instance) -> #v2_charging_id{instance = Instance, id = M_id}; -decode_v2_element(<>, 95, Instance) -> +decode_v2_element(<>, 95, Instance) -> #v2_charging_characteristics{instance = Instance, value = M_value}; -decode_v2_element(<<>>, 96, Instance) -> - #v2_trace_information{instance = Instance}; - -decode_v2_element(<<>>, 97, Instance) -> - #v2_bearer_flags{instance = Instance}; +decode_v2_element(<>, 96, Instance) -> + #v2_trace_information{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + trace_id = M_trace_id, + triggering_events = M_triggering_events, + list_of_ne_types = M_list_of_ne_types, + session_trace_depth = M_session_trace_depth, + list_of_interfaces = M_list_of_interfaces, + ip_address_of_trace_collection_entity = M_ip_address_of_trace_collection_entity}; + +decode_v2_element(<>, 97, Instance) -> + #v2_bearer_flags{instance = Instance, + flags = decode_flags(binary:decode_unsigned(M_flags, little), ['PCC','VB', + 'Vind','ASI', + '_','_','_', + '_'])}; decode_v2_element(<<_:4, M_pdn_type:4/integer, @@ -3077,8 +3414,10 @@ decode_v2_element(<<_:4, #v2_pdn_type{instance = Instance, pdn_type = enum_v2_pdn_type(M_pdn_type)}; -decode_v2_element(<<>>, 100, Instance) -> - #v2_procedure_transaction_id{instance = Instance}; +decode_v2_element(<>, 100, Instance) -> + #v2_procedure_transaction_id{instance = Instance, + pti = M_pti}; decode_v2_element(<<>>, 103, Instance) -> #v2_mm_context_1{instance = Instance}; @@ -3098,20 +3437,36 @@ decode_v2_element(<<>>, 107, Instance) -> decode_v2_element(<<>>, 108, Instance) -> #v2_mm_context_6{instance = Instance}; -decode_v2_element(<<>>, 109, Instance) -> - #v2_pdn_connection{instance = Instance}; - -decode_v2_element(<<>>, 110, Instance) -> - #v2_pdu_numbers{instance = Instance}; - -decode_v2_element(<<>>, 111, Instance) -> - #v2_p_tmsi{instance = Instance}; - -decode_v2_element(<<>>, 112, Instance) -> - #v2_p_tmsi_signature{instance = Instance}; +decode_v2_element(<>, 109, Instance) -> + #v2_pdn_connection{instance = Instance, + group = decode_v2_grouped(M_group)}; -decode_v2_element(<<>>, 113, Instance) -> - #v2_hop_counter{instance = Instance}; +decode_v2_element(<<_:4, + M_nsapi:4/integer, + M_dl_gtp_u_sequence_number:16/integer, + M_ul_gtp_u_sequence_number:16/integer, + M_send_n_pdu_number:16/integer, + M_receive_n_pdu_number:16/integer, + _/binary>>, 110, Instance) -> + #v2_pdu_numbers{instance = Instance, + nsapi = M_nsapi, + dl_gtp_u_sequence_number = M_dl_gtp_u_sequence_number, + ul_gtp_u_sequence_number = M_ul_gtp_u_sequence_number, + send_n_pdu_number = M_send_n_pdu_number, + receive_n_pdu_number = M_receive_n_pdu_number}; + +decode_v2_element(<>, 111, Instance) -> + #v2_p_tmsi{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 112, Instance) -> + #v2_p_tmsi_signature{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 113, Instance) -> + #v2_hop_counter{instance = Instance, + hop_counter = M_hop_counter}; decode_v2_element(<>, 115, Instance) -> - #v2_trace_reference{instance = Instance}; - -decode_v2_element(<<>>, 116, Instance) -> - #v2_complete_request_message{instance = Instance}; - -decode_v2_element(<<>>, 117, Instance) -> - #v2_guti{instance = Instance}; - -decode_v2_element(<<>>, 118, Instance) -> - #v2_f_container{instance = Instance}; - -decode_v2_element(<<>>, 119, Instance) -> - #v2_f_cause{instance = Instance}; - -decode_v2_element(<<>>, 120, Instance) -> - #v2_plmn_id{instance = Instance}; +decode_v2_element(<>, 115, Instance) -> + #v2_trace_reference{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + id = M_id}; + +decode_v2_element(<>, 116, Instance) -> + #v2_complete_request_message{instance = Instance, + type = M_type, + message = M_message}; + +decode_v2_element(<>, 117, Instance) -> + #v2_guti{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + group_id = M_group_id, + code = M_code, + m_tmsi = M_m_tmsi}; -decode_v2_element(<<>>, 121, Instance) -> - #v2_target_identification{instance = Instance}; - -decode_v2_element(<<>>, 123, Instance) -> - #v2_packet_flow_id_{instance = Instance}; - -decode_v2_element(<<>>, 124, Instance) -> - #v2_rab_context_{instance = Instance}; +decode_v2_element(<<_:4, + M_type:4/integer, + M_data/binary>>, 118, Instance) -> + #v2_f_container{instance = Instance, + type = M_type, + data = M_data}; -decode_v2_element(<<>>, 125, Instance) -> - #v2_source_rnc_pdcp_context_info{instance = Instance}; +decode_v2_element(<<_:4, + M_type:4/integer, + M_data/binary>>, 119, Instance) -> + #v2_f_cause{instance = Instance, + type = M_type, + data = M_data}; + +decode_v2_element(<>, 120, Instance) -> + #v2_plmn_id{instance = Instance, + id = M_id}; + +decode_v2_element(<>, 121, Instance) -> + #v2_target_identification{instance = Instance, + type = M_type, + data = M_data}; -decode_v2_element(<<>>, 126, Instance) -> - #v2_udp_source_port_number{instance = Instance}; +decode_v2_element(<<_:4, + M_ebi:4/integer, + M_flow_id/binary>>, 123, Instance) -> + #v2_packet_flow_id{instance = Instance, + ebi = M_ebi, + flow_id = M_flow_id}; + +decode_v2_element(<>, 124, Instance) -> + #v2_rab_context{instance = Instance, + ulpsi = M_ulpsi, + dlpsi = M_dlpsi, + ulgsi = M_ulgsi, + dlgsi = M_dlgsi, + nsapi = M_nsapi, + dl_gtp_u_sequence_number = M_dl_gtp_u_sequence_number, + ul_gtp_u_sequence_number = M_ul_gtp_u_sequence_number, + dl_pdcp_number = M_dl_pdcp_number, + ul_pdcp_number = M_ul_pdcp_number}; + +decode_v2_element(<>, 125, Instance) -> + #v2_source_rnc_pdcp_context_info{instance = Instance, + rrc_container = M_rrc_container}; + +decode_v2_element(<>, 126, Instance) -> + #v2_udp_source_port_number{instance = Instance, + port = M_port}; decode_v2_element(<>, 127, Instance) -> @@ -3165,32 +3571,42 @@ decode_v2_element(<<_:6, #v2_selection_mode{instance = Instance, mode = M_mode}; -decode_v2_element(<<>>, 129, Instance) -> - #v2_source_identification{instance = Instance}; +decode_v2_element(<>, 129, Instance) -> + #v2_source_identification{instance = Instance, + target_cell_id = M_target_cell_id, + source_type = M_source_type, + source_id = M_source_id}; decode_v2_element(<>, 131, Instance) -> #v2_change_reporting_action{instance = Instance, action = enum_v2_action(M_action)}; -decode_v2_element(<<>>, 132, Instance) -> - #v2_fully_qualified_pdn_connection_set_identifier{instance = Instance}; +decode_v2_element(<>, 132, Instance) -> + decode_v2_fully_qualified_pdn_connection_set_identifier(Data, Instance); -decode_v2_element(<<>>, 133, Instance) -> - #v2_channel_needed{instance = Instance}; +decode_v2_element(<>, 133, Instance) -> + #v2_channel_needed{instance = Instance, + value = M_value}; -decode_v2_element(<<>>, 134, Instance) -> - #v2_emlpp_priority{instance = Instance}; +decode_v2_element(<>, 134, Instance) -> + #v2_emlpp_priority{instance = Instance, + value = M_value}; -decode_v2_element(<<>>, 135, Instance) -> - #v2_node_type{instance = Instance}; +decode_v2_element(<>, 135, Instance) -> + #v2_node_type{instance = Instance, + node_type = M_node_type}; decode_v2_element(<>, 136, Instance) -> #v2_fully_qualified_domain_name{instance = Instance, fqdn = decode_fqdn(M_fqdn)}; -decode_v2_element(<<>>, 137, Instance) -> - #v2_transaction_identifier{instance = Instance}; +decode_v2_element(<>, 137, Instance) -> + #v2_transaction_identifier{instance = Instance, + value = M_value}; decode_v2_element(<<>>, 138, Instance) -> #v2_mbms_session_duration{instance = Instance}; @@ -3210,101 +3626,209 @@ decode_v2_element(<<>>, 142, Instance) -> decode_v2_element(<<>>, 143, Instance) -> #v2_mbms_distribution_acknowledge{instance = Instance}; -decode_v2_element(<<>>, 144, Instance) -> - #v2_rfsp_index{instance = Instance}; - -decode_v2_element(<<>>, 145, Instance) -> - #v2_user_csg_information{instance = Instance}; - -decode_v2_element(<<>>, 146, Instance) -> - #v2_csg_information_reporting_action{instance = Instance}; - -decode_v2_element(<<>>, 147, Instance) -> - #v2_csg_id{instance = Instance}; - -decode_v2_element(<<>>, 148, Instance) -> - #v2_csg_membership_indication{instance = Instance}; +decode_v2_element(<>, 144, Instance) -> + #v2_rfsp_index{instance = Instance, + value = M_value}; -decode_v2_element(<<>>, 149, Instance) -> - #v2_service_indicator{instance = Instance}; - -decode_v2_element(<<>>, 150, Instance) -> - #v2_detach_type{instance = Instance}; +decode_v2_element(<>, 145, Instance) -> + #v2_user_csg_information{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + csg_id = M_csg_id, + access_mode = M_access_mode, + lcsg = int2bool(M_lcsg), + cmi = M_cmi}; + +decode_v2_element(<>, 146, Instance) -> + #v2_csg_information_reporting_action{instance = Instance, + actions = decode_flags(binary:decode_unsigned(M_actions, little), ['UCICSG', + 'UCISHC', + 'UCIUHC', + '_','_', + '_','_', + '_'])}; -decode_v2_element(<<>>, 151, Instance) -> - #v2_local_distiguished_name{instance = Instance}; +decode_v2_element(<<_:5, + M_id:27/bits, + _/binary>>, 147, Instance) -> + #v2_csg_id{instance = Instance, + id = M_id}; -decode_v2_element(<<>>, 152, Instance) -> - #v2_node_features{instance = Instance}; +decode_v2_element(<<_:7, + M_cmi:1/integer, + _/binary>>, 148, Instance) -> + #v2_csg_membership_indication{instance = Instance, + cmi = M_cmi}; + +decode_v2_element(<>, 149, Instance) -> + #v2_service_indicator{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 150, Instance) -> + #v2_detach_type{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 151, Instance) -> + #v2_local_distiguished_name{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 152, Instance) -> + #v2_node_features{instance = Instance, + features = decode_flags(binary:decode_unsigned(M_features, little), ['PRN', + 'MABR', + 'NTSR', + 'CIOT', + 'S1UN', + 'ETH', + '_','_'])}; decode_v2_element(<<>>, 153, Instance) -> #v2_mbms_time_to_data_transfer{instance = Instance}; -decode_v2_element(<<>>, 154, Instance) -> - #v2_throttling{instance = Instance}; - -decode_v2_element(<<>>, 155, Instance) -> - #v2_allocation_retention_priority{instance = Instance}; +decode_v2_element(<>, 154, Instance) -> + #v2_throttling{instance = Instance, + unit = M_unit, + value = M_value, + factor = M_factor}; -decode_v2_element(<<>>, 156, Instance) -> - #v2_epc_timer{instance = Instance}; +decode_v2_element(<<_:1, + M_pci:1/integer, + M_pl:4/integer, + _:1, + M_pvi:1/integer, + _/binary>>, 155, Instance) -> + #v2_allocation_retention_priority{instance = Instance, + pci = int2bool(M_pci), + pl = M_pl, + pvi = int2bool(M_pvi)}; + +decode_v2_element(<>, 156, Instance) -> + #v2_epc_timer{instance = Instance, + unit = M_unit, + value = M_value}; -decode_v2_element(<<>>, 157, Instance) -> - #v2_signalling_priority_indication{instance = Instance}; +decode_v2_element(<>, 157, Instance) -> + #v2_signalling_priority_indication{instance = Instance, + indication = decode_flags(binary:decode_unsigned(M_indication, little), ['LAPI', + '_', + '_', + '_', + '_', + '_', + '_', + '_'])}; decode_v2_element(<<>>, 158, Instance) -> #v2_temporary_mobile_group_identity{instance = Instance}; -decode_v2_element(<<>>, 159, Instance) -> - #v2_additional_mm_context_for_srvcc{instance = Instance}; - -decode_v2_element(<<>>, 160, Instance) -> - #v2_additional_flags_for_srvcc{instance = Instance}; +decode_v2_element(<>, 159, Instance) -> + #v2_additional_mm_context_for_srvcc{instance = Instance, + classmark_2 = M_classmark_2, + classmark_3 = M_classmark_3, + codec_list = M_codec_list}; + +decode_v2_element(<>, 160, Instance) -> + #v2_additional_flags_for_srvcc{instance = Instance, + flags = decode_flags(binary:decode_unsigned(M_flags, little), ['ICS','VF','_', + '_','_','_', + '_','_'])}; decode_v2_element(<<>>, 162, Instance) -> #v2_mdt_configuration{instance = Instance}; -decode_v2_element(<<>>, 163, Instance) -> - #v2_additional_protocol_configuration_options{instance = Instance}; +decode_v2_element(<>, 163, Instance) -> + #v2_additional_protocol_configuration_options{instance = Instance, + config = decode_protocol_config_opts(M_config)}; decode_v2_element(<<>>, 164, Instance) -> #v2_absolute_time_of_mbms_data_transfer{instance = Instance}; -decode_v2_element(<<>>, 165, Instance) -> - #v2_henb_information_reporting_{instance = Instance}; - -decode_v2_element(<<>>, 166, Instance) -> - #v2_ipv4_configuration_parameters{instance = Instance}; +decode_v2_element(<>, 165, Instance) -> + #v2_henb_information_reporting_{instance = Instance, + flags = decode_flags(binary:decode_unsigned(M_flags, little), ['FTI','_','_', + '_','_','_', + '_','_'])}; + +decode_v2_element(<>, 166, Instance) -> + #v2_ipv4_configuration_parameters{instance = Instance, + prefix_length = M_prefix_length, + default_route = M_default_route}; + +decode_v2_element(<>, 167, Instance) -> + #v2_change_to_report_flags_{instance = Instance, + flags = decode_flags(binary:decode_unsigned(M_flags, little), ['SNCR','TZCR', + '_','_','_', + '_','_','_'])}; -decode_v2_element(<<>>, 167, Instance) -> - #v2_change_to_report_flags_{instance = Instance}; - -decode_v2_element(<<>>, 168, Instance) -> - #v2_action_indication{instance = Instance}; +decode_v2_element(<<_:5, + M_indication:3/integer, + _/binary>>, 168, Instance) -> + #v2_action_indication{instance = Instance, + indication = M_indication}; -decode_v2_element(<<>>, 169, Instance) -> - #v2_twan_identifier{instance = Instance}; +decode_v2_element(<>, 169, Instance) -> + decode_v2_twan_identifier(Data, Instance); -decode_v2_element(<<>>, 170, Instance) -> - #v2_uli_timestamp{instance = Instance}; +decode_v2_element(<>, 170, Instance) -> + #v2_uli_timestamp{instance = Instance, + timestamp = M_timestamp}; decode_v2_element(<<>>, 171, Instance) -> #v2_mbms_flags{instance = Instance}; -decode_v2_element(<<>>, 172, Instance) -> - #v2_ran_nas_cause{instance = Instance}; - -decode_v2_element(<<>>, 173, Instance) -> - #v2_cn_operator_selection_entity{instance = Instance}; +decode_v2_element(<>, 172, Instance) -> + #v2_ran_nas_cause{instance = Instance, + protocol = M_protocol, + type = M_type, + cause = M_cause}; -decode_v2_element(<<>>, 174, Instance) -> - #v2_trusted_wlan_mode_indication{instance = Instance}; - -decode_v2_element(<<>>, 175, Instance) -> - #v2_node_number{instance = Instance}; - -decode_v2_element(<<>>, 176, Instance) -> - #v2_node_identifier{instance = Instance}; +decode_v2_element(<<_:6, + M_entity:2/integer, + _/binary>>, 173, Instance) -> + #v2_cn_operator_selection_entity{instance = Instance, + entity = M_entity}; + +decode_v2_element(<>, 174, Instance) -> + #v2_trusted_wlan_mode_indication{instance = Instance, + indication = decode_flags(binary:decode_unsigned(M_indication, little), ['SCM', + 'MCM', + '_', + '_', + '_', + '_', + '_', + '_'])}; + +decode_v2_element(<>, 175, Instance) -> + #v2_node_number{instance = Instance, + number = M_number}; + +decode_v2_element(<>, 176, Instance) -> + #v2_node_identifier{instance = Instance, + name = M_name, + realm = M_realm}; decode_v2_element(<<>>, 177, Instance) -> #v2_presence_reporting_area_action{instance = Instance}; @@ -3312,29 +3836,195 @@ decode_v2_element(<<>>, 177, Instance) -> decode_v2_element(<<>>, 178, Instance) -> #v2_presence_reporting_area_information{instance = Instance}; -decode_v2_element(<<>>, 179, Instance) -> - #v2_twan_identifier_timestamp{instance = Instance}; - -decode_v2_element(<<>>, 180, Instance) -> - #v2_overload_control_information{instance = Instance}; - -decode_v2_element(<<>>, 181, Instance) -> - #v2_load_control_information{instance = Instance}; +decode_v2_element(<>, 179, Instance) -> + #v2_twan_identifier_timestamp{instance = Instance, + timestamp = M_timestamp}; + +decode_v2_element(<>, 180, Instance) -> + #v2_overload_control_information{instance = Instance, + group = decode_v2_grouped(M_group)}; + +decode_v2_element(<>, 181, Instance) -> + #v2_load_control_information{instance = Instance, + group = decode_v2_grouped(M_group)}; + +decode_v2_element(<>, 182, Instance) -> + #v2_metric{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 183, Instance) -> + #v2_sequence_number{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 184, Instance) -> + #v2_apn_and_relative_capacity{instance = Instance, + capacity = M_capacity, + apn = M_apn}; + +decode_v2_element(<>, 185, Instance) -> + #v2_wlan_offloadability_indication{instance = Instance, + indication = decode_flags(binary:decode_unsigned(M_indication, little), ['UTRAN', + 'EUTRAN', + '_', + '_', + '_', + '_', + '_', + '_'])}; + +decode_v2_element(<>, 186, Instance) -> + decode_v2_paging_and_service_information(Data, Instance); + +decode_v2_element(<>, 187, Instance) -> + decode_v2_integer_number(Data, Instance); + +decode_v2_element(<>, 188, Instance) -> + #v2_millisecond_time_stamp{instance = Instance, + timestamp = M_timestamp}; + +decode_v2_element(<<>>, 189, Instance) -> + #v2_monitoring_event_information{instance = Instance}; + +decode_v2_element(<>, 190, Instance) -> + M_ecgis_size = M_ecgis_len * 7 * 8, + <> = M_ecgis_Rest, + #v2_ecgi_list{instance = Instance, + ecgis = [X || <> <= M_ecgis]}; + +decode_v2_element(<>, 191, Instance) -> + #v2_remote_ue_context{instance = Instance, + group = decode_v2_grouped(M_group)}; + +decode_v2_element(<>, 192, Instance) -> + decode_v2_remote_user_id(Data, Instance); + +decode_v2_element(<>, 193, Instance) -> + #v2_remote_ue_ip_information{instance = Instance, + ip = M_ip}; + +decode_v2_element(<>, 194, Instance) -> + #v2_ciot_optimizations_support_indication{instance = Instance, + indication = decode_flags(binary:decode_unsigned(M_indication, little), ['SGNIPDN', + 'SCNIPDN', + 'AWOPDN', + 'IHCSI', + '_', + '_', + '_', + '_'])}; + +decode_v2_element(<>, 195, Instance) -> + #v2_scef_pdn_connection{instance = Instance, + group = decode_v2_grouped(M_group)}; + +decode_v2_element(<>, 196, Instance) -> + #v2_header_compression_configuration{instance = Instance, + rohc_profiles = M_rohc_profiles, + max_cid = M_max_cid}; + +decode_v2_element(<>, 197, Instance) -> + #v2_extended_protocol_configuration_options{instance = Instance, + config = decode_protocol_config_opts(M_config)}; + +decode_v2_element(<>, 198, Instance) -> + #v2_serving_plmn_rate_control{instance = Instance, + uplink = M_uplink, + downlink = M_downlink}; + +decode_v2_element(<>, 199, Instance) -> + #v2_counter{instance = Instance, + timestamp = M_timestamp, + counter = M_counter}; + +decode_v2_element(<>, 200, Instance) -> + #v2_mapped_ue_usage_type{instance = Instance, + usage_type = M_usage_type}; -decode_v2_element(<<>>, 182, Instance) -> - #v2_metric{instance = Instance}; - -decode_v2_element(<<>>, 183, Instance) -> - #v2_sequence_number{instance = Instance}; - -decode_v2_element(<<>>, 184, Instance) -> - #v2_apn_and_relative_capacity{instance = Instance}; - -decode_v2_element(<<>>, 185, Instance) -> - #v2_wlan_offloadability_indication{instance = Instance}; - -decode_v2_element(<<>>, 255, Instance) -> - #v2_private_extension{instance = Instance}; +decode_v2_element(<<_:6, + M_irsgw:1/integer, + M_irpgw:1/integer, + M_rat_type:8/integer, + _:4, + M_ebi:4/integer, + M_start_time:32/integer, + M_end_time:32/integer, + M_dl:64/integer, + M_ul:64/integer, + _/binary>>, 201, Instance) -> + #v2_secondary_rat_usage_data_report{instance = Instance, + irsgw = int2bool(M_irsgw), + irpgw = int2bool(M_irpgw), + rat_type = M_rat_type, + ebi = M_ebi, + start_time = M_start_time, + end_time = M_end_time, + dl = M_dl, + ul = M_ul}; + +decode_v2_element(<>, 202, Instance) -> + #v2_up_function_selection_indication_flags{instance = Instance, + indication = decode_flags(binary:decode_unsigned(M_indication, little), ['DCNR', + '_', + '_', + '_', + '_', + '_', + '_', + '_'])}; + +decode_v2_element(<>, 203, Instance) -> + decode_v2_maximum_packet_loss_rate(Data, Instance); + +decode_v2_element(<>, 204, Instance) -> + #v2_apn_rate_control_status{instance = Instance, + number_of_uplink_packets_allowed = M_number_of_uplink_packets_allowed, + number_of_additional_exception_reports = M_number_of_additional_exception_reports, + number_of_downlink_packets_allowed = M_number_of_downlink_packets_allowed, + apn_rate_control_status_validity_time = M_apn_rate_control_status_validity_time}; + +decode_v2_element(<>, 205, Instance) -> + #v2_extended_trace_information{instance = Instance, + mcc = decode_mcc(M_mccmnc), + mnc = decode_mnc(M_mccmnc), + trace_id = M_trace_id, + triggering_events = M_triggering_events, + list_of_ne_types = M_list_of_ne_types, + session_trace_depth = M_session_trace_depth, + list_of_interfaces = M_list_of_interfaces, + ip_address_of_trace_collection_entity = M_ip_address_of_trace_collection_entity}; + +decode_v2_element(<>, 206, Instance) -> + decode_v2_monitoring_event_extension_information(Data, Instance); + +decode_v2_element(<>, 207, Instance) -> + #v2_additional_rrm_policy_index{instance = Instance, + value = M_value}; + +decode_v2_element(<>, 255, Instance) -> + decode_v2_private_extension(Data, Instance); decode_v2_element(Value, Tag, Instance) -> {Tag, Instance, Value}. @@ -3349,17 +4039,32 @@ encode_v2_element(#v2_cause{ v2_cause = M_v2_cause, pce = M_pce, bce = M_bce, - cs = M_cs}) -> + cs = M_cs, + offending_ie = undefined}) -> + encode_v2_element(2, Instance, <<(enum_v2_v2_cause(M_v2_cause)):8/integer, + 0:5, + M_pce:1/integer, + M_bce:1/integer, + M_cs:1/integer>>); + +encode_v2_element(#v2_cause{ + instance = Instance, + v2_cause = M_v2_cause, + pce = M_pce, + bce = M_bce, + cs = M_cs, + offending_ie = M_offending_ie}) -> encode_v2_element(2, Instance, <<(enum_v2_v2_cause(M_v2_cause)):8/integer, 0:5, - M_pce:1, - M_bce:1, - M_cs:1>>); + M_pce:1/integer, + M_bce:1/integer, + M_cs:1/integer, + M_offending_ie:4/bytes>>); encode_v2_element(#v2_recovery{ instance = Instance, restart_counter = M_restart_counter}) -> - encode_v2_element(3, Instance, <>); + encode_v2_element(3, Instance, <>); encode_v2_element(#v2_stn_sr{ instance = Instance}) -> @@ -3374,14 +4079,14 @@ encode_v2_element(#v2_aggregate_maximum_bit_rate{ instance = Instance, uplink = M_uplink, downlink = M_downlink}) -> - encode_v2_element(72, Instance, <>); + encode_v2_element(72, Instance, <>); encode_v2_element(#v2_eps_bearer_id{ instance = Instance, eps_bearer_id = M_eps_bearer_id}) -> encode_v2_element(73, Instance, <<0:4, - M_eps_bearer_id:4>>); + M_eps_bearer_id:4/integer>>); encode_v2_element(#v2_ip_address{ instance = Instance, @@ -3401,7 +4106,23 @@ encode_v2_element(#v2_msisdn{ encode_v2_element(#v2_indication{ instance = Instance, flags = M_flags}) -> - encode_v2_element(77, Instance, <<(encode_v2_indication_flags(M_flags))/binary>>); + encode_v2_element(77, Instance, <<(binary:encode_unsigned(encode_flags(M_flags, ['SGWCI','ISRAI','ISRSI','OI', + 'DFI','HI','DTF','DAF','MSV', + 'SI','PT','P','CRSI','CFSI', + 'UIMSI','SQCI','CCRSI','ISRAU', + 'MBMDT','S4AF','S6AF','SRNI', + 'PBIC','RetLoc','CPSR','CLII', + 'CSFBI','PPSI','PPON/PPEI', + 'PPOF','ARRL','CPRAI','AOPI', + 'AOSI','PCRI','PSCI','BDWI', + 'DTCI','UASI','NSI','WPMSI', + 'UNACCSI','PNSI','S11TF', + 'PMTSMI','CPOPCI','EPCOSI', + 'ROAAI','TSPCMI','ENBCRSI', + 'LTEMPI','LTEMUI','EEVRSI', + '5GSIWK','REPREFI','5GSNN26', + 'ETHPDN','5SRHOI','5GCNRI', + '5GCNRS','N5GNMI','_','_','_']), little))/binary>>); encode_v2_element(#v2_protocol_configuration_options{ instance = Instance, @@ -3427,35 +4148,49 @@ encode_v2_element(#v2_bearer_level_quality_of_service{ guaranteed_bit_rate_for_uplink = M_guaranteed_bit_rate_for_uplink, guaranteed_bit_rate_for_downlink = M_guaranteed_bit_rate_for_downlink}) -> encode_v2_element(80, Instance, <<0:1, - M_pci:1, - M_pl:4, + M_pci:1/integer, + M_pl:4/integer, 0:1, - M_pvi:1, - M_label:8, - M_maximum_bit_rate_for_uplink:40, - M_maximum_bit_rate_for_downlink:40, - M_guaranteed_bit_rate_for_uplink:40, - M_guaranteed_bit_rate_for_downlink:40>>); + M_pvi:1/integer, + M_label:8/integer, + M_maximum_bit_rate_for_uplink:40/integer, + M_maximum_bit_rate_for_downlink:40/integer, + M_guaranteed_bit_rate_for_uplink:40/integer, + M_guaranteed_bit_rate_for_downlink:40/integer>>); encode_v2_element(#v2_flow_quality_of_service{ - instance = Instance}) -> - encode_v2_element(81, Instance, <<>>); + instance = Instance, + label = M_label, + maximum_bit_rate_for_uplink = M_maximum_bit_rate_for_uplink, + maximum_bit_rate_for_downlink = M_maximum_bit_rate_for_downlink, + guaranteed_bit_rate_for_uplink = M_guaranteed_bit_rate_for_uplink, + guaranteed_bit_rate_for_downlink = M_guaranteed_bit_rate_for_downlink}) -> + encode_v2_element(81, Instance, <>); encode_v2_element(#v2_rat_type{ instance = Instance, rat_type = M_rat_type}) -> - encode_v2_element(82, Instance, <>); + encode_v2_element(82, Instance, <>); -encode_v2_element(#v2_serving_network{instance = Instance} = IE) -> - encode_v2_element(83, Instance, encode_v2_mccmnc(IE)); +encode_v2_element(#v2_serving_network{ + instance = Instance, + mcc = M_mcc, + mnc = M_mnc}) -> + encode_v2_element(83, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary>>); encode_v2_element(#v2_eps_bearer_level_traffic_flow_template{ - instance = Instance}) -> - encode_v2_element(84, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(84, Instance, <>); encode_v2_element(#v2_traffic_aggregation_description{ - instance = Instance}) -> - encode_v2_element(85, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(85, Instance, <>); encode_v2_element(#v2_user_location_information{instance = Instance} = IE) -> encode_v2_element(86, Instance, encode_v2_user_location_information(IE)); @@ -3464,24 +4199,38 @@ encode_v2_element(#v2_fully_qualified_tunnel_endpoint_identifier{instance = Inst encode_v2_element(87, Instance, encode_v2_fully_qualified_tunnel_endpoint_identifier(IE)); encode_v2_element(#v2_tmsi{ - instance = Instance}) -> - encode_v2_element(88, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(88, Instance, <>); encode_v2_element(#v2_global_cn_id{ - instance = Instance}) -> - encode_v2_element(89, Instance, <<>>); + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + value = M_value}) -> + encode_v2_element(89, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + M_value/binary>>); encode_v2_element(#v2_s103_pdn_data_forwarding_info{ - instance = Instance}) -> - encode_v2_element(90, Instance, <<>>); + instance = Instance, + hsgw_address = M_hsgw_address, + gre_key = M_gre_key, + eps_bearer_id = M_eps_bearer_id}) -> + encode_v2_element(90, Instance, <<(byte_size(M_hsgw_address)):8/integer, M_hsgw_address/binary, + M_gre_key:32/integer, + (length(M_eps_bearer_id)):8/integer, (<< <> || X <- M_eps_bearer_id>>)/binary>>); encode_v2_element(#v2_s1_u_data_forwarding_info{ - instance = Instance}) -> - encode_v2_element(91, Instance, <<>>); + instance = Instance, + service_gw_address = M_service_gw_address, + teid = M_teid}) -> + encode_v2_element(91, Instance, <<(byte_size(M_service_gw_address)):8/integer, M_service_gw_address/binary, + M_teid:32/integer>>); encode_v2_element(#v2_delay_value{ - instance = Instance}) -> - encode_v2_element(92, Instance, <<>>); + instance = Instance, + delay = M_delay}) -> + encode_v2_element(92, Instance, <>); encode_v2_element(#v2_bearer_context{ instance = Instance, @@ -3499,12 +4248,28 @@ encode_v2_element(#v2_charging_characteristics{ encode_v2_element(95, Instance, <>); encode_v2_element(#v2_trace_information{ - instance = Instance}) -> - encode_v2_element(96, Instance, <<>>); + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + trace_id = M_trace_id, + triggering_events = M_triggering_events, + list_of_ne_types = M_list_of_ne_types, + session_trace_depth = M_session_trace_depth, + list_of_interfaces = M_list_of_interfaces, + ip_address_of_trace_collection_entity = M_ip_address_of_trace_collection_entity}) -> + encode_v2_element(96, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + M_trace_id:32/integer, + M_triggering_events:9/bytes, + M_list_of_ne_types:16/integer, + M_session_trace_depth:8/integer, + M_list_of_interfaces:12/bytes, + M_ip_address_of_trace_collection_entity/binary>>); encode_v2_element(#v2_bearer_flags{ - instance = Instance}) -> - encode_v2_element(97, Instance, <<>>); + instance = Instance, + flags = M_flags}) -> + encode_v2_element(97, Instance, <<(binary:encode_unsigned(encode_flags(M_flags, ['PCC','VB','Vind','ASI','_', + '_','_','_']), little))/binary>>); encode_v2_element(#v2_pdn_type{ instance = Instance, @@ -3513,8 +4278,9 @@ encode_v2_element(#v2_pdn_type{ (enum_v2_pdn_type(M_pdn_type)):4/integer>>); encode_v2_element(#v2_procedure_transaction_id{ - instance = Instance}) -> - encode_v2_element(100, Instance, <<>>); + instance = Instance, + pti = M_pti}) -> + encode_v2_element(100, Instance, <>); encode_v2_element(#v2_mm_context_1{ instance = Instance}) -> @@ -3541,112 +4307,183 @@ encode_v2_element(#v2_mm_context_6{ encode_v2_element(108, Instance, <<>>); encode_v2_element(#v2_pdn_connection{ - instance = Instance}) -> - encode_v2_element(109, Instance, <<>>); + instance = Instance, + group = M_group}) -> + encode_v2_element(109, Instance, <<(encode_v2_grouped(M_group))/binary>>); encode_v2_element(#v2_pdu_numbers{ - instance = Instance}) -> - encode_v2_element(110, Instance, <<>>); + instance = Instance, + nsapi = M_nsapi, + dl_gtp_u_sequence_number = M_dl_gtp_u_sequence_number, + ul_gtp_u_sequence_number = M_ul_gtp_u_sequence_number, + send_n_pdu_number = M_send_n_pdu_number, + receive_n_pdu_number = M_receive_n_pdu_number}) -> + encode_v2_element(110, Instance, <<0:4, + M_nsapi:4/integer, + M_dl_gtp_u_sequence_number:16/integer, + M_ul_gtp_u_sequence_number:16/integer, + M_send_n_pdu_number:16/integer, + M_receive_n_pdu_number:16/integer>>); encode_v2_element(#v2_p_tmsi{ - instance = Instance}) -> - encode_v2_element(111, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(111, Instance, <>); encode_v2_element(#v2_p_tmsi_signature{ - instance = Instance}) -> - encode_v2_element(112, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(112, Instance, <>); encode_v2_element(#v2_hop_counter{ - instance = Instance}) -> - encode_v2_element(113, Instance, <<>>); + instance = Instance, + hop_counter = M_hop_counter}) -> + encode_v2_element(113, Instance, <>); encode_v2_element(#v2_ue_time_zone{ instance = Instance, timezone = M_timezone, dst = M_dst}) -> - encode_v2_element(114, Instance, <>); + M_dst:2/integer>>); encode_v2_element(#v2_trace_reference{ - instance = Instance}) -> - encode_v2_element(115, Instance, <<>>); + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + id = M_id}) -> + encode_v2_element(115, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + M_id:24/integer>>); encode_v2_element(#v2_complete_request_message{ - instance = Instance}) -> - encode_v2_element(116, Instance, <<>>); + instance = Instance, + type = M_type, + message = M_message}) -> + encode_v2_element(116, Instance, <>); encode_v2_element(#v2_guti{ - instance = Instance}) -> - encode_v2_element(117, Instance, <<>>); + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + group_id = M_group_id, + code = M_code, + m_tmsi = M_m_tmsi}) -> + encode_v2_element(117, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + M_group_id:16/integer, + M_code:24/integer, + M_m_tmsi/binary>>); encode_v2_element(#v2_f_container{ - instance = Instance}) -> - encode_v2_element(118, Instance, <<>>); + instance = Instance, + type = M_type, + data = M_data}) -> + encode_v2_element(118, Instance, <<0:4, + M_type:4/integer, + M_data/binary>>); encode_v2_element(#v2_f_cause{ - instance = Instance}) -> - encode_v2_element(119, Instance, <<>>); + instance = Instance, + type = M_type, + data = M_data}) -> + encode_v2_element(119, Instance, <<0:4, + M_type:4/integer, + M_data/binary>>); encode_v2_element(#v2_plmn_id{ - instance = Instance}) -> - encode_v2_element(120, Instance, <<>>); + instance = Instance, + id = M_id}) -> + encode_v2_element(120, Instance, <>); encode_v2_element(#v2_target_identification{ - instance = Instance}) -> - encode_v2_element(121, Instance, <<>>); + instance = Instance, + type = M_type, + data = M_data}) -> + encode_v2_element(121, Instance, <>); -encode_v2_element(#v2_packet_flow_id_{ - instance = Instance}) -> - encode_v2_element(123, Instance, <<>>); +encode_v2_element(#v2_packet_flow_id{ + instance = Instance, + ebi = M_ebi, + flow_id = M_flow_id}) -> + encode_v2_element(123, Instance, <<0:4, + M_ebi:4/integer, + M_flow_id/binary>>); -encode_v2_element(#v2_rab_context_{ - instance = Instance}) -> - encode_v2_element(124, Instance, <<>>); +encode_v2_element(#v2_rab_context{ + instance = Instance, + ulpsi = M_ulpsi, + dlpsi = M_dlpsi, + ulgsi = M_ulgsi, + dlgsi = M_dlgsi, + nsapi = M_nsapi, + dl_gtp_u_sequence_number = M_dl_gtp_u_sequence_number, + ul_gtp_u_sequence_number = M_ul_gtp_u_sequence_number, + dl_pdcp_number = M_dl_pdcp_number, + ul_pdcp_number = M_ul_pdcp_number}) -> + encode_v2_element(124, Instance, <>); encode_v2_element(#v2_source_rnc_pdcp_context_info{ - instance = Instance}) -> - encode_v2_element(125, Instance, <<>>); + instance = Instance, + rrc_container = M_rrc_container}) -> + encode_v2_element(125, Instance, <>); encode_v2_element(#v2_udp_source_port_number{ - instance = Instance}) -> - encode_v2_element(126, Instance, <<>>); + instance = Instance, + port = M_port}) -> + encode_v2_element(126, Instance, <>); encode_v2_element(#v2_apn_restriction{ instance = Instance, restriction_type_value = M_restriction_type_value}) -> - encode_v2_element(127, Instance, <>); + encode_v2_element(127, Instance, <>); encode_v2_element(#v2_selection_mode{ instance = Instance, mode = M_mode}) -> encode_v2_element(128, Instance, <<0:6, - M_mode:2>>); + M_mode:2/integer>>); encode_v2_element(#v2_source_identification{ - instance = Instance}) -> - encode_v2_element(129, Instance, <<>>); + instance = Instance, + target_cell_id = M_target_cell_id, + source_type = M_source_type, + source_id = M_source_id}) -> + encode_v2_element(129, Instance, <>); encode_v2_element(#v2_change_reporting_action{ instance = Instance, action = M_action}) -> encode_v2_element(131, Instance, <<(enum_v2_action(M_action)):8/integer>>); -encode_v2_element(#v2_fully_qualified_pdn_connection_set_identifier{ - instance = Instance}) -> - encode_v2_element(132, Instance, <<>>); +encode_v2_element(#v2_fully_qualified_pdn_connection_set_identifier{instance = Instance} = IE) -> + encode_v2_element(132, Instance, encode_v2_fully_qualified_pdn_connection_set_identifier(IE)); encode_v2_element(#v2_channel_needed{ - instance = Instance}) -> - encode_v2_element(133, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(133, Instance, <>); encode_v2_element(#v2_emlpp_priority{ - instance = Instance}) -> - encode_v2_element(134, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(134, Instance, <>); encode_v2_element(#v2_node_type{ - instance = Instance}) -> - encode_v2_element(135, Instance, <<>>); + instance = Instance, + node_type = M_node_type}) -> + encode_v2_element(135, Instance, <>); encode_v2_element(#v2_fully_qualified_domain_name{ instance = Instance, @@ -3654,8 +4491,9 @@ encode_v2_element(#v2_fully_qualified_domain_name{ encode_v2_element(136, Instance, <<(encode_fqdn(M_fqdn))/binary>>); encode_v2_element(#v2_transaction_identifier{ - instance = Instance}) -> - encode_v2_element(137, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(137, Instance, <>); encode_v2_element(#v2_mbms_session_duration{ instance = Instance}) -> @@ -3682,132 +4520,203 @@ encode_v2_element(#v2_mbms_distribution_acknowledge{ encode_v2_element(143, Instance, <<>>); encode_v2_element(#v2_rfsp_index{ - instance = Instance}) -> - encode_v2_element(144, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(144, Instance, <>); encode_v2_element(#v2_user_csg_information{ - instance = Instance}) -> - encode_v2_element(145, Instance, <<>>); + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + csg_id = M_csg_id, + access_mode = M_access_mode, + lcsg = M_lcsg, + cmi = M_cmi}) -> + encode_v2_element(145, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + 0:5, + M_csg_id:27/bits, + M_access_mode:2/integer, + 0:4, + (bool2int(M_lcsg)):1/integer, + M_cmi:1/integer>>); encode_v2_element(#v2_csg_information_reporting_action{ - instance = Instance}) -> - encode_v2_element(146, Instance, <<>>); + instance = Instance, + actions = M_actions}) -> + encode_v2_element(146, Instance, <<(binary:encode_unsigned(encode_flags(M_actions, ['UCICSG','UCISHC','UCIUHC', + '_','_','_','_','_']), little))/binary>>); encode_v2_element(#v2_csg_id{ - instance = Instance}) -> - encode_v2_element(147, Instance, <<>>); + instance = Instance, + id = M_id}) -> + encode_v2_element(147, Instance, <<0:5, + M_id:27/bits>>); encode_v2_element(#v2_csg_membership_indication{ - instance = Instance}) -> - encode_v2_element(148, Instance, <<>>); + instance = Instance, + cmi = M_cmi}) -> + encode_v2_element(148, Instance, <<0:7, + M_cmi:1/integer>>); encode_v2_element(#v2_service_indicator{ - instance = Instance}) -> - encode_v2_element(149, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(149, Instance, <>); encode_v2_element(#v2_detach_type{ - instance = Instance}) -> - encode_v2_element(150, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(150, Instance, <>); encode_v2_element(#v2_local_distiguished_name{ - instance = Instance}) -> - encode_v2_element(151, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(151, Instance, <>); encode_v2_element(#v2_node_features{ - instance = Instance}) -> - encode_v2_element(152, Instance, <<>>); + instance = Instance, + features = M_features}) -> + encode_v2_element(152, Instance, <<(binary:encode_unsigned(encode_flags(M_features, ['PRN','MABR','NTSR','CIOT', + 'S1UN','ETH','_','_']), little))/binary>>); encode_v2_element(#v2_mbms_time_to_data_transfer{ instance = Instance}) -> encode_v2_element(153, Instance, <<>>); encode_v2_element(#v2_throttling{ - instance = Instance}) -> - encode_v2_element(154, Instance, <<>>); + instance = Instance, + unit = M_unit, + value = M_value, + factor = M_factor}) -> + encode_v2_element(154, Instance, <>); encode_v2_element(#v2_allocation_retention_priority{ - instance = Instance}) -> - encode_v2_element(155, Instance, <<>>); + instance = Instance, + pci = M_pci, + pl = M_pl, + pvi = M_pvi}) -> + encode_v2_element(155, Instance, <<0:1, + (bool2int(M_pci)):1/integer, + M_pl:4/integer, + 0:1, + (bool2int(M_pvi)):1/integer>>); encode_v2_element(#v2_epc_timer{ - instance = Instance}) -> - encode_v2_element(156, Instance, <<>>); + instance = Instance, + unit = M_unit, + value = M_value}) -> + encode_v2_element(156, Instance, <>); encode_v2_element(#v2_signalling_priority_indication{ - instance = Instance}) -> - encode_v2_element(157, Instance, <<>>); + instance = Instance, + indication = M_indication}) -> + encode_v2_element(157, Instance, <<(binary:encode_unsigned(encode_flags(M_indication, ['LAPI','_','_','_','_', + '_','_','_']), little))/binary>>); encode_v2_element(#v2_temporary_mobile_group_identity{ instance = Instance}) -> encode_v2_element(158, Instance, <<>>); encode_v2_element(#v2_additional_mm_context_for_srvcc{ - instance = Instance}) -> - encode_v2_element(159, Instance, <<>>); + instance = Instance, + classmark_2 = M_classmark_2, + classmark_3 = M_classmark_3, + codec_list = M_codec_list}) -> + encode_v2_element(159, Instance, <<(byte_size(M_classmark_2)):8/integer, M_classmark_2/binary, + (byte_size(M_classmark_3)):8/integer, M_classmark_3/binary, + (byte_size(M_codec_list)):8/integer, M_codec_list/binary>>); encode_v2_element(#v2_additional_flags_for_srvcc{ - instance = Instance}) -> - encode_v2_element(160, Instance, <<>>); + instance = Instance, + flags = M_flags}) -> + encode_v2_element(160, Instance, <<(binary:encode_unsigned(encode_flags(M_flags, ['ICS','VF','_','_','_','_','_', + '_']), little))/binary>>); encode_v2_element(#v2_mdt_configuration{ instance = Instance}) -> encode_v2_element(162, Instance, <<>>); encode_v2_element(#v2_additional_protocol_configuration_options{ - instance = Instance}) -> - encode_v2_element(163, Instance, <<>>); + instance = Instance, + config = M_config}) -> + encode_v2_element(163, Instance, <<(encode_protocol_config_opts(M_config))/binary>>); encode_v2_element(#v2_absolute_time_of_mbms_data_transfer{ instance = Instance}) -> encode_v2_element(164, Instance, <<>>); encode_v2_element(#v2_henb_information_reporting_{ - instance = Instance}) -> - encode_v2_element(165, Instance, <<>>); + instance = Instance, + flags = M_flags}) -> + encode_v2_element(165, Instance, <<(binary:encode_unsigned(encode_flags(M_flags, ['FTI','_','_','_','_','_','_', + '_']), little))/binary>>); encode_v2_element(#v2_ipv4_configuration_parameters{ - instance = Instance}) -> - encode_v2_element(166, Instance, <<>>); + instance = Instance, + prefix_length = M_prefix_length, + default_route = M_default_route}) -> + encode_v2_element(166, Instance, <>); encode_v2_element(#v2_change_to_report_flags_{ - instance = Instance}) -> - encode_v2_element(167, Instance, <<>>); + instance = Instance, + flags = M_flags}) -> + encode_v2_element(167, Instance, <<(binary:encode_unsigned(encode_flags(M_flags, ['SNCR','TZCR','_','_','_','_', + '_','_']), little))/binary>>); encode_v2_element(#v2_action_indication{ - instance = Instance}) -> - encode_v2_element(168, Instance, <<>>); + instance = Instance, + indication = M_indication}) -> + encode_v2_element(168, Instance, <<0:5, + M_indication:3/integer>>); -encode_v2_element(#v2_twan_identifier{ - instance = Instance}) -> - encode_v2_element(169, Instance, <<>>); +encode_v2_element(#v2_twan_identifier{instance = Instance} = IE) -> + encode_v2_element(169, Instance, encode_v2_twan_identifier(IE)); encode_v2_element(#v2_uli_timestamp{ - instance = Instance}) -> - encode_v2_element(170, Instance, <<>>); + instance = Instance, + timestamp = M_timestamp}) -> + encode_v2_element(170, Instance, <>); encode_v2_element(#v2_mbms_flags{ instance = Instance}) -> encode_v2_element(171, Instance, <<>>); encode_v2_element(#v2_ran_nas_cause{ - instance = Instance}) -> - encode_v2_element(172, Instance, <<>>); + instance = Instance, + protocol = M_protocol, + type = M_type, + cause = M_cause}) -> + encode_v2_element(172, Instance, <>); encode_v2_element(#v2_cn_operator_selection_entity{ - instance = Instance}) -> - encode_v2_element(173, Instance, <<>>); + instance = Instance, + entity = M_entity}) -> + encode_v2_element(173, Instance, <<0:6, + M_entity:2/integer>>); encode_v2_element(#v2_trusted_wlan_mode_indication{ - instance = Instance}) -> - encode_v2_element(174, Instance, <<>>); + instance = Instance, + indication = M_indication}) -> + encode_v2_element(174, Instance, <<(binary:encode_unsigned(encode_flags(M_indication, ['SCM','MCM','_','_','_', + '_','_','_']), little))/binary>>); encode_v2_element(#v2_node_number{ - instance = Instance}) -> - encode_v2_element(175, Instance, <<>>); + instance = Instance, + number = M_number}) -> + encode_v2_element(175, Instance, <<(byte_size(M_number)):8/integer, M_number/binary>>); encode_v2_element(#v2_node_identifier{ - instance = Instance}) -> - encode_v2_element(176, Instance, <<>>); + instance = Instance, + name = M_name, + realm = M_realm}) -> + encode_v2_element(176, Instance, <<(byte_size(M_name)):8/integer, M_name/binary, + (byte_size(M_realm)):8/integer, M_realm/binary>>); encode_v2_element(#v2_presence_reporting_area_action{ instance = Instance}) -> @@ -3818,36 +4727,188 @@ encode_v2_element(#v2_presence_reporting_area_information{ encode_v2_element(178, Instance, <<>>); encode_v2_element(#v2_twan_identifier_timestamp{ - instance = Instance}) -> - encode_v2_element(179, Instance, <<>>); + instance = Instance, + timestamp = M_timestamp}) -> + encode_v2_element(179, Instance, <>); encode_v2_element(#v2_overload_control_information{ - instance = Instance}) -> - encode_v2_element(180, Instance, <<>>); + instance = Instance, + group = M_group}) -> + encode_v2_element(180, Instance, <<(encode_v2_grouped(M_group))/binary>>); encode_v2_element(#v2_load_control_information{ - instance = Instance}) -> - encode_v2_element(181, Instance, <<>>); + instance = Instance, + group = M_group}) -> + encode_v2_element(181, Instance, <<(encode_v2_grouped(M_group))/binary>>); encode_v2_element(#v2_metric{ - instance = Instance}) -> - encode_v2_element(182, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(182, Instance, <>); encode_v2_element(#v2_sequence_number{ - instance = Instance}) -> - encode_v2_element(183, Instance, <<>>); + instance = Instance, + value = M_value}) -> + encode_v2_element(183, Instance, <>); encode_v2_element(#v2_apn_and_relative_capacity{ - instance = Instance}) -> - encode_v2_element(184, Instance, <<>>); + instance = Instance, + capacity = M_capacity, + apn = M_apn}) -> + encode_v2_element(184, Instance, <>); encode_v2_element(#v2_wlan_offloadability_indication{ - instance = Instance}) -> - encode_v2_element(185, Instance, <<>>); + instance = Instance, + indication = M_indication}) -> + encode_v2_element(185, Instance, <<(binary:encode_unsigned(encode_flags(M_indication, ['UTRAN','EUTRAN','_','_', + '_','_','_','_']), little))/binary>>); + +encode_v2_element(#v2_paging_and_service_information{instance = Instance} = IE) -> + encode_v2_element(186, Instance, encode_v2_paging_and_service_information(IE)); + +encode_v2_element(#v2_integer_number{instance = Instance} = IE) -> + encode_v2_element(187, Instance, encode_v2_integer_number(IE)); + +encode_v2_element(#v2_millisecond_time_stamp{ + instance = Instance, + timestamp = M_timestamp}) -> + encode_v2_element(188, Instance, <>); -encode_v2_element(#v2_private_extension{ +encode_v2_element(#v2_monitoring_event_information{ instance = Instance}) -> - encode_v2_element(255, Instance, <<>>); + encode_v2_element(189, Instance, <<>>); + +encode_v2_element(#v2_ecgi_list{ + instance = Instance, + ecgis = M_ecgis}) -> + encode_v2_element(190, Instance, <<(length(M_ecgis)):16/integer, (<< <> || X <- M_ecgis>>)/binary>>); + +encode_v2_element(#v2_remote_ue_context{ + instance = Instance, + group = M_group}) -> + encode_v2_element(191, Instance, <<(encode_v2_grouped(M_group))/binary>>); + +encode_v2_element(#v2_remote_user_id{instance = Instance} = IE) -> + encode_v2_element(192, Instance, encode_v2_remote_user_id(IE)); + +encode_v2_element(#v2_remote_ue_ip_information{ + instance = Instance, + ip = M_ip}) -> + encode_v2_element(193, Instance, <>); + +encode_v2_element(#v2_ciot_optimizations_support_indication{ + instance = Instance, + indication = M_indication}) -> + encode_v2_element(194, Instance, <<(binary:encode_unsigned(encode_flags(M_indication, ['SGNIPDN','SCNIPDN', + 'AWOPDN','IHCSI','_','_', + '_','_']), little))/binary>>); + +encode_v2_element(#v2_scef_pdn_connection{ + instance = Instance, + group = M_group}) -> + encode_v2_element(195, Instance, <<(encode_v2_grouped(M_group))/binary>>); + +encode_v2_element(#v2_header_compression_configuration{ + instance = Instance, + rohc_profiles = M_rohc_profiles, + max_cid = M_max_cid}) -> + encode_v2_element(196, Instance, <>); + +encode_v2_element(#v2_extended_protocol_configuration_options{ + instance = Instance, + config = M_config}) -> + encode_v2_element(197, Instance, <<(encode_protocol_config_opts(M_config))/binary>>); + +encode_v2_element(#v2_serving_plmn_rate_control{ + instance = Instance, + uplink = M_uplink, + downlink = M_downlink}) -> + encode_v2_element(198, Instance, <>); + +encode_v2_element(#v2_counter{ + instance = Instance, + timestamp = M_timestamp, + counter = M_counter}) -> + encode_v2_element(199, Instance, <>); + +encode_v2_element(#v2_mapped_ue_usage_type{ + instance = Instance, + usage_type = M_usage_type}) -> + encode_v2_element(200, Instance, <>); + +encode_v2_element(#v2_secondary_rat_usage_data_report{ + instance = Instance, + irsgw = M_irsgw, + irpgw = M_irpgw, + rat_type = M_rat_type, + ebi = M_ebi, + start_time = M_start_time, + end_time = M_end_time, + dl = M_dl, + ul = M_ul}) -> + encode_v2_element(201, Instance, <<0:6, + (bool2int(M_irsgw)):1/integer, + (bool2int(M_irpgw)):1/integer, + M_rat_type:8/integer, + 0:4, + M_ebi:4/integer, + M_start_time:32/integer, + M_end_time:32/integer, + M_dl:64/integer, + M_ul:64/integer>>); + +encode_v2_element(#v2_up_function_selection_indication_flags{ + instance = Instance, + indication = M_indication}) -> + encode_v2_element(202, Instance, <<(binary:encode_unsigned(encode_flags(M_indication, ['DCNR','_','_','_','_', + '_','_','_']), little))/binary>>); + +encode_v2_element(#v2_maximum_packet_loss_rate{instance = Instance} = IE) -> + encode_v2_element(203, Instance, encode_v2_maximum_packet_loss_rate(IE)); + +encode_v2_element(#v2_apn_rate_control_status{ + instance = Instance, + number_of_uplink_packets_allowed = M_number_of_uplink_packets_allowed, + number_of_additional_exception_reports = M_number_of_additional_exception_reports, + number_of_downlink_packets_allowed = M_number_of_downlink_packets_allowed, + apn_rate_control_status_validity_time = M_apn_rate_control_status_validity_time}) -> + encode_v2_element(204, Instance, <>); + +encode_v2_element(#v2_extended_trace_information{ + instance = Instance, + mcc = M_mcc, + mnc = M_mnc, + trace_id = M_trace_id, + triggering_events = M_triggering_events, + list_of_ne_types = M_list_of_ne_types, + session_trace_depth = M_session_trace_depth, + list_of_interfaces = M_list_of_interfaces, + ip_address_of_trace_collection_entity = M_ip_address_of_trace_collection_entity}) -> + encode_v2_element(205, Instance, <<(encode_mccmnc(M_mcc, M_mnc))/binary, + M_trace_id:32/integer, + (byte_size(M_triggering_events)):8/integer, M_triggering_events/binary, + (byte_size(M_list_of_ne_types)):8/integer, M_list_of_ne_types/binary, + M_session_trace_depth:8/integer, + (byte_size(M_list_of_interfaces)):8/integer, M_list_of_interfaces/binary, + (byte_size(M_ip_address_of_trace_collection_entity)):8/integer, M_ip_address_of_trace_collection_entity/binary>>); + +encode_v2_element(#v2_monitoring_event_extension_information{instance = Instance} = IE) -> + encode_v2_element(206, Instance, encode_v2_monitoring_event_extension_information(IE)); + +encode_v2_element(#v2_additional_rrm_policy_index{ + instance = Instance, + value = M_value}) -> + encode_v2_element(207, Instance, <>); + +encode_v2_element(#v2_private_extension{instance = Instance} = IE) -> + encode_v2_element(255, Instance, encode_v2_private_extension(IE)); encode_v2_element({Tag, Instance, Value}) when is_integer(Tag), is_integer(Instance), is_binary(Value) -> encode_v2_element(Tag, Instance, Value). @@ -3904,8 +4965,8 @@ encode_v2_element({Tag, Instance, Value}) when is_integer(Tag), is_integer(Insta ?PRETTY_PRINT(pretty_print_v2, v2_f_cause); ?PRETTY_PRINT(pretty_print_v2, v2_plmn_id); ?PRETTY_PRINT(pretty_print_v2, v2_target_identification); -?PRETTY_PRINT(pretty_print_v2, v2_packet_flow_id_); -?PRETTY_PRINT(pretty_print_v2, v2_rab_context_); +?PRETTY_PRINT(pretty_print_v2, v2_packet_flow_id); +?PRETTY_PRINT(pretty_print_v2, v2_rab_context); ?PRETTY_PRINT(pretty_print_v2, v2_source_rnc_pdcp_context_info); ?PRETTY_PRINT(pretty_print_v2, v2_udp_source_port_number); ?PRETTY_PRINT(pretty_print_v2, v2_apn_restriction); @@ -3965,6 +5026,28 @@ encode_v2_element({Tag, Instance, Value}) when is_integer(Tag), is_integer(Insta ?PRETTY_PRINT(pretty_print_v2, v2_sequence_number); ?PRETTY_PRINT(pretty_print_v2, v2_apn_and_relative_capacity); ?PRETTY_PRINT(pretty_print_v2, v2_wlan_offloadability_indication); +?PRETTY_PRINT(pretty_print_v2, v2_paging_and_service_information); +?PRETTY_PRINT(pretty_print_v2, v2_integer_number); +?PRETTY_PRINT(pretty_print_v2, v2_millisecond_time_stamp); +?PRETTY_PRINT(pretty_print_v2, v2_monitoring_event_information); +?PRETTY_PRINT(pretty_print_v2, v2_ecgi_list); +?PRETTY_PRINT(pretty_print_v2, v2_remote_ue_context); +?PRETTY_PRINT(pretty_print_v2, v2_remote_user_id); +?PRETTY_PRINT(pretty_print_v2, v2_remote_ue_ip_information); +?PRETTY_PRINT(pretty_print_v2, v2_ciot_optimizations_support_indication); +?PRETTY_PRINT(pretty_print_v2, v2_scef_pdn_connection); +?PRETTY_PRINT(pretty_print_v2, v2_header_compression_configuration); +?PRETTY_PRINT(pretty_print_v2, v2_extended_protocol_configuration_options); +?PRETTY_PRINT(pretty_print_v2, v2_serving_plmn_rate_control); +?PRETTY_PRINT(pretty_print_v2, v2_counter); +?PRETTY_PRINT(pretty_print_v2, v2_mapped_ue_usage_type); +?PRETTY_PRINT(pretty_print_v2, v2_secondary_rat_usage_data_report); +?PRETTY_PRINT(pretty_print_v2, v2_up_function_selection_indication_flags); +?PRETTY_PRINT(pretty_print_v2, v2_maximum_packet_loss_rate); +?PRETTY_PRINT(pretty_print_v2, v2_apn_rate_control_status); +?PRETTY_PRINT(pretty_print_v2, v2_extended_trace_information); +?PRETTY_PRINT(pretty_print_v2, v2_monitoring_event_extension_information); +?PRETTY_PRINT(pretty_print_v2, v2_additional_rrm_policy_index); ?PRETTY_PRINT(pretty_print_v2, v2_private_extension); pretty_print_v2(_, _) -> no. diff --git a/test/gtp_SUITE.erl b/test/gtp_SUITE.erl index 4021053..dd9b783 100644 --- a/test/gtp_SUITE.erl +++ b/test/gtp_SUITE.erl @@ -14,7 +14,7 @@ %%%------------------------------------------------------------------- -module(gtp_SUITE). --compile(export_all). +-compile([export_all, nowarn_export_all]). -include_lib("common_test/include/ct.hrl"). -include("../include/gtp_packet.hrl"). @@ -58,8 +58,10 @@ all() -> test_v1_ignore_spare_bits, test_g_pdu, test_v2_pco_vendor_ext, + v2_list, partial_decode, partial_encode, + flags_enc_dec, msg_enc_dec]. @@ -272,6 +274,62 @@ test_v2_pco_vendor_ext(_Config) -> ?match(Data when is_binary(Data), (catch gtp_packet:encode(Msg))), ok. +v2_list(_Config) -> + IEs = + [ + #v2_bearer_context{ + instance = 0, + group = [#v2_bearer_level_quality_of_service{ + pci = 1,pl = 10,pvi = 0,label = 8, + maximum_bit_rate_for_uplink = 0, + maximum_bit_rate_for_downlink = 0, + guaranteed_bit_rate_for_uplink = 0, + guaranteed_bit_rate_for_downlink = 0}, + #v2_eps_bearer_id{eps_bearer_id = 5}, + #v2_fully_qualified_tunnel_endpoint_identifier{ + instance = 2, + interface_type = 4,key = 1,ipv4 = <<127,0,0,1>>, + ipv6 = undefined}]}, + #v2_bearer_context{ + instance = 0, + group = [#v2_bearer_level_quality_of_service{ + pci = 1,pl = 10,pvi = 0,label = 8, + maximum_bit_rate_for_uplink = 0, + maximum_bit_rate_for_downlink = 0, + guaranteed_bit_rate_for_uplink = 0, + guaranteed_bit_rate_for_downlink = 0}, + #v2_eps_bearer_id{eps_bearer_id = 5}, + #v2_fully_qualified_tunnel_endpoint_identifier{ + instance = 2, + interface_type = 4,key = 2,ipv4 = <<127,0,0,1>>, + ipv6 = undefined}]}, + #v2_bearer_context{ + instance = 0, + group = [#v2_bearer_level_quality_of_service{ + pci = 1,pl = 10,pvi = 0,label = 8, + maximum_bit_rate_for_uplink = 0, + maximum_bit_rate_for_downlink = 0, + guaranteed_bit_rate_for_uplink = 0, + guaranteed_bit_rate_for_downlink = 0}, + #v2_eps_bearer_id{eps_bearer_id = 5}, + #v2_fully_qualified_tunnel_endpoint_identifier{ + instance = 2, + interface_type = 4,key = 3,ipv4 = <<127,0,0,1>>, + ipv6 = undefined}]} + ], + Msg = #gtp{version = v2, + type = create_session_request, + seq_no = 1, + tei = 0, + ie = IEs}, + Bin = (catch gtp_packet:encode(Msg)), + ?equal(true, is_binary(Bin)), + + #gtp{version = v2, ie = M} = gtp_packet:decode(Bin), + BC = maps:get({v2_bearer_context, 0}, M), + ?equal(3, length(BC)), + ok. + partial_decode(_Config) -> Msg0 = gtp_packet:decode(get_msg(v1, create_pdp_context_request_2), #{ies => binary}), ?match(#gtp{ie = IEs} when is_binary(IEs), Msg0), @@ -317,6 +375,46 @@ partial_encode(_Config) -> ?match(_ when is_binary(Msg12), Msg12), ok. +flags_enc_dec(_Config) -> + Bin1 = <<72,1,0,13,0,0,0,0,0,0,0,0,77,0,1,0,128>>, + Msg1 = #gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} => + #v2_indication{instance = 0,flags = ['DAF']}}}, + ?match(<<72,1,0,13,0,0,0,0,0,0,0,0,77,0,1,0,128>>, gtp_packet:encode(Msg1)), + ?match(#gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} := + #v2_indication{instance = 0,flags = ['DAF']}}}, + gtp_packet:decode(Bin1)), + + Bin2 = <<72,1,0,14,0,0,0,0,0,0,0,0,77,0,2,0,0,8>>, + Msg2 = #gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} => + #v2_indication{instance = 0,flags = ['P']}}}, + ?match(<<72,1,0,14,0,0,0,0,0,0,0,0,77,0,2,0,0,8>>, gtp_packet:encode(Msg2)), + ?match(#gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} := + #v2_indication{instance = 0,flags = ['P']}}}, + gtp_packet:decode(Bin2)), + + %% unkown indication flag, make sure it passed through enc/dec + Bin3 = <<72,1,0,22,0,0,0,0,0,0,0,0,77,0,10,0,0,0,0,0,0,0,0,0,0,8>>, + Msg3 = #gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} => + #v2_indication{instance = 0,flags = [2048]}}}, + ?match(<<72,1,0,22,0,0,0,0,0,0,0,0,77,0,10,0,0,0,0,0,0,0,0,0,0,8>>, + gtp_packet:encode(Msg3)), + ?match(#gtp{version = v2,type = echo_request,tei = 0,seq_no = 0, + n_pdu = undefined,ext_hdr = [], + ie = #{{v2_indication,0} := + #v2_indication{instance = 0,flags = [2048]}}}, + gtp_packet:decode(Bin3)), + ok. + msg_enc_dec() -> [{doc, "Check that Message encoding/decoding matches"}]. msg_enc_dec(Config) -> diff --git a/test/property_test/gtplib_prop.erl b/test/property_test/gtplib_prop.erl index 9c0d5c1..9e863d2 100644 --- a/test/property_test/gtplib_prop.erl +++ b/test/property_test/gtplib_prop.erl @@ -131,6 +131,21 @@ gen_pcap(Cnt) -> %%% Internal functions %%%=================================================================== +%% from the proper manual +list_no_dupls(T) -> + ?LET(L, list(T), remove_duplicates(L)). + +%% better versions of remove_duplicates/1 exist ... +remove_duplicates([]) -> []; +remove_duplicates([A|T]) -> + case lists:member(A, T) of + true -> remove_duplicates(T); + false -> [A|remove_duplicates(T)] + end. + +flags(Flags) -> + list_no_dupls(oneof(Flags)). + flag() -> oneof([0,1]). @@ -153,17 +168,20 @@ mcc() -> ?LET(I, integer(1,999), integer_to_binary(I)). mcc_label() -> - ?LET(I, mcc(), list_to_binary(io_lib:format("mcc~3..0s", [I]))). + ?LET(M, mcc(), list_to_binary(io_lib:format("mcc~3..0s", [M]))). mnc() -> - ?LET(I, integer(1,999), integer_to_binary(I)). + ?LET(M, integer(1,999), integer_to_binary(M)). mnc_label() -> - ?LET(I, mnc(), list_to_binary(io_lib:format("mnc~3..0s", [I]))). + ?LET(M, mnc(), list_to_binary(io_lib:format("mnc~3..0s", [M]))). apn() -> ?LET(L, [dns_name(), mnc_label(), mcc_label(), <<"gprs">>], lists:flatten(L)). +uint4() -> + integer(0,16#0f). + uint8() -> integer(0,16#ff). @@ -192,7 +210,7 @@ ip46_address() -> binary(20). instance() -> - integer(0,15). + uint4(). tei() -> uint32(). @@ -204,6 +222,9 @@ binstr_number(Min, Max) -> ?LET(X, ?LET(I, integer(Min,Max), vector(I, integer($0, $9))), list_to_binary(X)). +binary(Min, Max) -> + ?LET(I, integer(Min,Max), binary(I)). + imsi() -> binstr_number(7,15). @@ -519,7 +540,10 @@ v1_simple_ie() -> gen_private_extension()]). v2_grouped_ie() -> - [gen_v2_bearer_context()]. + [gen_v2_bearer_context(), + gen_v2_pdn_connection(), + gen_v2_overload_control_information(), + gen_v2_load_control_information()]. v2_simple_ie() -> [gen_v2_international_mobile_subscriber_identity(), @@ -540,6 +564,8 @@ v2_simple_ie() -> gen_v2_rat_type(), gen_v2_eps_bearer_level_traffic_flow_template(), gen_v2_traffic_aggregation_description(), + gen_v2_user_location_information(), + gen_v2_fully_qualified_tunnel_endpoint_identifier(), gen_v2_tmsi(), gen_v2_global_cn_id(), gen_v2_s103_pdn_data_forwarding_info(), @@ -557,7 +583,6 @@ v2_simple_ie() -> gen_v2_mm_context_4(), gen_v2_mm_context_5(), gen_v2_mm_context_6(), - gen_v2_pdn_connection(), gen_v2_pdu_numbers(), gen_v2_p_tmsi(), gen_v2_p_tmsi_signature(), @@ -570,8 +595,8 @@ v2_simple_ie() -> gen_v2_f_cause(), gen_v2_plmn_id(), gen_v2_target_identification(), - gen_v2_packet_flow_id_(), - gen_v2_rab_context_(), + gen_v2_packet_flow_id(), + gen_v2_rab_context(), gen_v2_source_rnc_pdcp_context_info(), gen_v2_udp_source_port_number(), gen_v2_apn_restriction(), @@ -625,8 +650,6 @@ v2_simple_ie() -> gen_v2_presence_reporting_area_action(), gen_v2_presence_reporting_area_information(), gen_v2_twan_identifier_timestamp(), - gen_v2_overload_control_information(), - gen_v2_load_control_information(), gen_v2_metric(), gen_v2_sequence_number(), gen_v2_apn_and_relative_capacity(), @@ -712,26 +735,6 @@ gen_user_location_information() -> rac = integer(0,255) }]). -%% gen_v2_user_location_information() -> -%% #v2_user_location_information{ -%% instance = instance(), -%% cgi, -%% sai, -%% rai, -%% tai, -%% ecgi, -%% lai -%% }. - -%% gen_v2_fully_qualified_tunnel_endpoint_identifier() -> -%% #v2_fully_qualified_tunnel_endpoint_identifier{ -%% instance = instance(), -%% interface_type, -%% key, -%% ipv4 = ip4_address(), -%% ipv6 = ip6_address() -%% }. - %% gen_v2_serving_network() -> %% #v2_serving_network{ %% instance = instance(), @@ -898,7 +901,7 @@ gen_teardown_ind() -> gen_nsapi() -> #nsapi{ instance = instance(), - nsapi = integer(0,15) + nsapi = uint4() }. gen_ranap_cause() -> @@ -965,7 +968,7 @@ gen_charging_id() -> gen_end_user_address() -> #end_user_address{ instance = instance(), - pdp_type_organization = integer(0,15), + pdp_type_organization = uint4(), pdp_type_number = integer(0,255), pdp_address = binary() }. @@ -974,7 +977,7 @@ gen_end_user_address() -> gen_mm_context_gsm() -> #mm_context_gsm{ instance = instance(), - cksn = integer(0,15), + cksn = uint4(), no_of_vectors = integer(0,7), used_cipher = integer(0,7), kc = binary(8), @@ -990,7 +993,7 @@ gen_mm_context_gsm() -> gen_mm_context_umts() -> #mm_context_umts{ instance = instance(), - ksi = integer(0,15), + ksi = uint4(), no_of_vectors = 0, ck = binary(16), ik = binary(16), @@ -1007,7 +1010,7 @@ gen_mm_context_umts() -> gen_mm_context_gsm_and_umts() -> #mm_context_gsm_and_umts{ instance = instance(), - cksn = integer(0,15), + cksn = uint4(), no_of_vectors = 0, used_cipher = integer(0,7), kc = binary(8), @@ -1024,7 +1027,7 @@ gen_mm_context_gsm_and_umts() -> gen_mm_context_umts_and_used_cipher() -> #mm_context_umts_and_used_cipher{ instance = instance(), - ksi = integer(0,15), + ksi = uint4(), no_of_vectors = 0, used_cipher = integer(0,7), ck = binary(16), @@ -1152,15 +1155,15 @@ gen_common_flags() -> #common_flags{ instance = instance(), flags = - list(oneof( - ['Dual Address Bearer Flag', - 'Upgrade QoS Supported', - 'NRSN', - 'No QoS negotiation', - 'MBMS Counting Information', - 'RAN Procedures Ready', - 'MBMS Service Type', - 'Prohibit Payload Compression'])) + flags( + ['Dual Address Bearer Flag', + 'Upgrade QoS Supported', + 'NRSN', + 'No QoS negotiation', + 'MBMS Counting Information', + 'RAN Procedures Ready', + 'MBMS Service Type', + 'Prohibit Payload Compression']) }. gen_apn_restriction() -> @@ -1373,7 +1376,7 @@ gen_evolved_allocation_retention_priority_i() -> #evolved_allocation_retention_priority_i{ instance = instance(), pci = oneof([0, 1]), - pl = integer(0, 15), + pl = uint4(), pvi = oneof([0, 1]) }. @@ -1386,7 +1389,7 @@ gen_extended_common_flags() -> #extended_common_flags{ instance = instance(), flags = - list(oneof(['CCRSI', 'CPSR', 'RetLoc', 'VB', 'PCRI', 'BDWI', 'UASI'])) + flags(['CCRSI', 'CPSR', 'RetLoc', 'VB', 'PCRI', 'BDWI', 'UASI']) }. gen_user_csg_information() -> @@ -1638,10 +1641,20 @@ gen_v2_cause() -> multiple_pdn_connections_for_a_given_apn_not_allowed, target_access_restricted_for_the_subscriber, mme_sgsn_refuses_due_to_vplmn_policy, - gtp_c_entity_congestion]), + gtp_c_entity_congestion, + late_overlapping_request, + timed_out_request, + ue_is_temporarily_not_reachable_due_to_power_saving, + relocation_failure_due_to_nas_message_redirection, + ue_not_authorised_by_ocs_or_external_aaa_server, + multiple_accesses_to_a_pdn_connection_not_allowed, + request_rejected_due_to_ue_capability, + s1_u_path_failure, + '5gc_not_allowed']), pce = oneof([0,1]), bce = oneof([0,1]), - cs = oneof([0,1]) + cs = oneof([0,1]), + offending_ie = oneof([undefined, binary(4)]) }. gen_v2_recovery() -> @@ -1671,7 +1684,7 @@ gen_v2_aggregate_maximum_bit_rate() -> gen_v2_eps_bearer_id() -> #v2_eps_bearer_id{ instance = instance(), - eps_bearer_id = integer(0,15) + eps_bearer_id = uint4() }. gen_v2_ip_address() -> @@ -1696,11 +1709,14 @@ gen_v2_indication() -> #v2_indication{ instance = instance(), flags = - list(oneof(['DAF', 'DTF', 'HI', 'DFI', 'OI', 'ISRSI', 'ISRAI', 'SGWCI', - 'SQCI', 'UIMSI', 'CFSI', 'CRSI', 'P', 'PT', 'SI', 'MSV', - 'RetLoc', 'PBIC', 'SRNI', 'S6AF', 'S4AF', 'MBMDT', 'ISRAU', 'CCRSI', - 'CPRAI', 'ARRL', 'PPOF', 'PPON/PPEI', 'PPSI', 'CSFBI', 'CLII', 'CPSR', - 'PSCI', 'PCRI', 'AOSI', 'AOPI'])) + flags( + ['DAF', 'DTF', 'HI', 'DFI', 'OI', 'ISRSI', 'ISRAI', 'SGWCI', + 'SQCI', 'UIMSI', 'CFSI', 'CRSI', 'P', 'PT', 'SI', 'MSV', + 'RetLoc', 'PBIC', 'SRNI', 'S6AF', 'S4AF', 'MBMDT', 'ISRAU', 'CCRSI', + 'CPRAI', 'ARRL', 'PPOF', 'PPON/PPEI', 'PPSI', 'CSFBI', 'CLII', 'CPSR', + 'NSI', 'UASI', 'DTCI', 'BDWI', 'PSCI', 'PCRI', 'AOSI', 'AOPI', + 'ROAAI', 'EPCOSI', 'CPOPCI', 'PMTSMI', 'S11TF', 'PNSI', 'UNACCSI', 'WPMSI', + '5GSNN26', 'REPREFI', '5GSIWK', 'EEVRSI', 'LTEMUI', 'LTEMPI', 'ENBCRSI', 'TSPCMI']) }. gen_v2_protocol_configuration_options() -> @@ -1731,7 +1747,7 @@ gen_v2_bearer_level_quality_of_service() -> #v2_bearer_level_quality_of_service{ instance = instance(), pci = oneof([0, 1]), - pl = integer(0,15), + pl = uint4(), pvi = oneof([0, 1]), label = uint8(), maximum_bit_rate_for_uplink = uint40(), @@ -1742,7 +1758,12 @@ gen_v2_bearer_level_quality_of_service() -> gen_v2_flow_quality_of_service() -> #v2_flow_quality_of_service{ - instance = instance() + instance = instance(), + label = uint8(), + maximum_bit_rate_for_uplink = uint40(), + maximum_bit_rate_for_downlink = uint40(), + guaranteed_bit_rate_for_uplink = uint40(), + guaranteed_bit_rate_for_downlink = uint40() }. gen_v2_rat_type() -> @@ -1753,27 +1774,69 @@ gen_v2_rat_type() -> gen_v2_eps_bearer_level_traffic_flow_template() -> #v2_eps_bearer_level_traffic_flow_template{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_traffic_aggregation_description() -> #v2_traffic_aggregation_description{ - instance = instance() + instance = instance(), + value = binary() + }. + +gen_v2_user_location_information() -> + #v2_user_location_information{ + instance = instance(), + cgi = oneof([undefined, binary(7)]), + sai = oneof([undefined, binary(7)]), + rai = oneof([undefined, binary(7)]), + tai = oneof([undefined, binary(5)]), + ecgi = oneof([undefined, binary(7)]), + lai = oneof([undefined, binary(5)]), + macro_enb = oneof([undefined, binary(6)]), + ext_macro_enb = oneof([undefined, binary(6)]) }. +gen_v2_fully_qualified_tunnel_endpoint_identifier() -> + oneof( + [#v2_fully_qualified_tunnel_endpoint_identifier{ + instance = instance(), + interface_type = uint8(), + key = uint32(), + ipv4 = ip4_address() + }, + #v2_fully_qualified_tunnel_endpoint_identifier{ + instance = instance(), + interface_type = uint8(), + key = uint32(), + ipv6 = ip6_address() + }, + #v2_fully_qualified_tunnel_endpoint_identifier{ + instance = instance(), + interface_type = uint8(), + key = uint32(), + ipv4 = ip4_address(), + ipv6 = ip6_address() + }]). + gen_v2_tmsi() -> #v2_tmsi{ - instance = instance() + instance = instance(), + value = uint32() }. gen_v2_global_cn_id() -> #v2_global_cn_id{ - instance = instance() + instance = instance(), + value = binary(7) }. gen_v2_s103_pdn_data_forwarding_info() -> #v2_s103_pdn_data_forwarding_info{ - instance = instance() + instance = instance(), + hsgw_address = oneof([ip4_address(),ip6_address()]), + gre_key = uint32(), + eps_bearer_id = list(uint8()) }. gen_v2_s1_u_data_forwarding_info() -> @@ -1783,7 +1846,8 @@ gen_v2_s1_u_data_forwarding_info() -> gen_v2_delay_value() -> #v2_delay_value{ - instance = instance() + instance = instance(), + delay = uint8() }. gen_v2_bearer_context() -> @@ -1805,12 +1869,22 @@ gen_v2_charging_characteristics() -> gen_v2_trace_information() -> #v2_trace_information{ - instance = instance() + instance = instance(), + mcc = mcc(), + mnc = mnc(), + trace_id = uint32(), + triggering_events = binary(9), + list_of_ne_types = uint16(), + session_trace_depth = uint8(), + list_of_interfaces = binary(12), + ip_address_of_trace_collection_entity = + oneof([ip4_address(), ip6_address()]) }. gen_v2_bearer_flags() -> #v2_bearer_flags{ - instance = instance() + instance = instance(), + flags = flags(['ASI', 'Vind', 'VB', 'PCC']) }. gen_v2_pdn_type() -> @@ -1821,7 +1895,8 @@ gen_v2_pdn_type() -> gen_v2_procedure_transaction_id() -> #v2_procedure_transaction_id{ - instance = instance() + instance = instance(), + pti = uint8() }. gen_v2_mm_context_1() -> @@ -1856,89 +1931,128 @@ gen_v2_mm_context_6() -> gen_v2_pdn_connection() -> #v2_pdn_connection{ - instance = instance() + instance = instance(), + group = v2_ie_group() }. gen_v2_pdu_numbers() -> #v2_pdu_numbers{ - instance = instance() + instance = instance(), + nsapi = uint4(), + dl_gtp_u_sequence_number = uint16(), + ul_gtp_u_sequence_number = uint16(), + send_n_pdu_number = uint16(), + receive_n_pdu_number = uint16() }. gen_v2_p_tmsi() -> #v2_p_tmsi{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_p_tmsi_signature() -> #v2_p_tmsi_signature{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_hop_counter() -> #v2_hop_counter{ - instance = instance() + instance = instance(), + hop_counter = uint8() }. gen_v2_ue_time_zone() -> #v2_ue_time_zone{ instance = instance(), timezone = uint8(), - dst = integer(0, 3) + dst = integer(0,3) }. gen_v2_trace_reference() -> #v2_trace_reference{ - instance = instance() + instance = instance(), + mcc = mcc(), + mnc = mnc(), + id = uint24() }. gen_v2_complete_request_message() -> #v2_complete_request_message{ - instance = instance() + instance = instance(), + type = uint8(), + message = binary() }. gen_v2_guti() -> #v2_guti{ - instance = instance() + instance = instance(), + mcc = mcc(), + mnc = mnc(), + group_id = uint16(), + code = uint24(), + m_tmsi = binary() }. gen_v2_f_container() -> #v2_f_container{ - instance = instance() + instance = instance(), + type = uint4(), + data = binary() }. gen_v2_f_cause() -> #v2_f_cause{ - instance = instance() + instance = instance(), + type = uint4(), + data = binary() }. gen_v2_plmn_id() -> #v2_plmn_id{ - instance = instance() + instance = instance(), + id = binary(3) }. gen_v2_target_identification() -> #v2_target_identification{ - instance = instance() + instance = instance(), + type = uint8(), + data = binary() }. -gen_v2_packet_flow_id_() -> - #v2_packet_flow_id_{ - instance = instance() +gen_v2_packet_flow_id() -> + #v2_packet_flow_id{ + instance = instance(), + ebi = uint4(), + flow_id = binary() }. -gen_v2_rab_context_() -> - #v2_rab_context_{ - instance = instance() +gen_v2_rab_context() -> + #v2_rab_context{ + instance = instance(), + ulpsi = flag(), + dlpsi = flag(), + ulgsi = flag(), + dlgsi = flag(), + nsapi = uint4(), + dl_gtp_u_sequence_number = uint16(), + ul_gtp_u_sequence_number = uint16(), + dl_pdcp_number = uint16(), + ul_pdcp_number = uint16() }. gen_v2_source_rnc_pdcp_context_info() -> #v2_source_rnc_pdcp_context_info{ - instance = instance() + instance = instance(), + rrc_container = binary() }. gen_v2_udp_source_port_number() -> #v2_udp_source_port_number{ - instance = instance() + instance = instance(), + port = uint16() }. gen_v2_apn_restriction() -> @@ -1955,7 +2069,10 @@ gen_v2_selection_mode() -> gen_v2_source_identification() -> #v2_source_identification{ - instance = instance() + instance = instance(), + target_cell_id = binary(8), + source_type = uint8(), + source_id = binary() }. gen_v2_change_reporting_action() -> @@ -1973,23 +2090,42 @@ gen_v2_change_reporting_action() -> }. gen_v2_fully_qualified_pdn_connection_set_identifier() -> - #v2_fully_qualified_pdn_connection_set_identifier{ - instance = instance() - }. + oneof([ + #v2_fully_qualified_pdn_connection_set_identifier{ + instance = instance(), + node_id_type = 0, + node_id = ip4_address(), + csids = ?LET(I, integer(0,15), vector(I, uint16())) + }, + #v2_fully_qualified_pdn_connection_set_identifier{ + instance = instance(), + node_id_type = 1, + node_id = ip6_address(), + csids = ?LET(I, integer(0,15), vector(I, uint16())) + }, + #v2_fully_qualified_pdn_connection_set_identifier{ + instance = instance(), + node_id_type = 2, + node_id = {integer(0,999), integer(0,999), integer(0,16#0fff)}, + csids = ?LET(I, integer(0,15), vector(I, uint16())) + }]). gen_v2_channel_needed() -> #v2_channel_needed{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_emlpp_priority() -> #v2_emlpp_priority{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_node_type() -> #v2_node_type{ - instance = instance() + instance = instance(), + node_type = uint8() }. gen_v2_fully_qualified_domain_name() -> @@ -2000,7 +2136,8 @@ gen_v2_fully_qualified_domain_name() -> gen_v2_transaction_identifier() -> #v2_transaction_identifier{ - instance = instance() + instance = instance(), + value = binary() }. gen_v2_mbms_session_duration() -> @@ -2035,47 +2172,62 @@ gen_v2_mbms_distribution_acknowledge() -> gen_v2_rfsp_index() -> #v2_rfsp_index{ - instance = instance() + instance = instance(), + value = uint16() }. gen_v2_user_csg_information() -> #v2_user_csg_information{ - instance = instance() + instance = instance(), + mcc = mcc(), + mnc = mnc(), + csg_id = bitstring(27), + access_mode = integer(0,3), + lcsg = boolean(), + cmi = flag() }. gen_v2_csg_information_reporting_action() -> #v2_csg_information_reporting_action{ - instance = instance() + instance = instance(), + actions = flags(['UCIUHC', 'UCISHC', 'UCICSG']) }. gen_v2_csg_id() -> #v2_csg_id{ - instance = instance() + instance = instance(), + id = bitstring(27) }. gen_v2_csg_membership_indication() -> #v2_csg_membership_indication{ - instance = instance() + instance = instance(), + cmi = flag() }. gen_v2_service_indicator() -> #v2_service_indicator{ - instance = instance() + instance = instance(), + value = uint8() }. gen_v2_detach_type() -> #v2_detach_type{ - instance = instance() + instance = instance(), + value = uint8() }. gen_v2_local_distiguished_name() -> #v2_local_distiguished_name{ - instance = instance() + instance = instance(), + value = binary(1, 400) }. gen_v2_node_features() -> #v2_node_features{ - instance = instance() + instance = instance(), + features = + flags(['ETH', 'S1UN', 'CIOT', 'NTSR', 'MABR', 'PRN']) }. gen_v2_mbms_time_to_data_transfer() -> @@ -2085,22 +2237,31 @@ gen_v2_mbms_time_to_data_transfer() -> gen_v2_throttling() -> #v2_throttling{ - instance = instance() + instance = instance(), + unit = integer(0,7), + value = integer(0,31), + factor = uint8() }. gen_v2_allocation_retention_priority() -> #v2_allocation_retention_priority{ - instance = instance() + instance = instance(), + pci = boolean(), + pl = uint4(), + pvi = boolean() }. gen_v2_epc_timer() -> #v2_epc_timer{ - instance = instance() + instance = instance(), + unit = integer(0,7), + value = integer(0,31) }. gen_v2_signalling_priority_indication() -> #v2_signalling_priority_indication{ - instance = instance() + instance = instance(), + indication = flags(['LAPI']) }. gen_v2_temporary_mobile_group_identity() -> @@ -2110,12 +2271,17 @@ gen_v2_temporary_mobile_group_identity() -> gen_v2_additional_mm_context_for_srvcc() -> #v2_additional_mm_context_for_srvcc{ - instance = instance() + instance = instance(), + classmark_2 = binary(), + classmark_3 = binary(), + codec_list = binary() + }. gen_v2_additional_flags_for_srvcc() -> #v2_additional_flags_for_srvcc{ - instance = instance() + instance = instance(), + flags = flags(['VF', 'ICS']) }. gen_v2_mdt_configuration() -> @@ -2125,7 +2291,8 @@ gen_v2_mdt_configuration() -> gen_v2_additional_protocol_configuration_options() -> #v2_additional_protocol_configuration_options{ - instance = instance() + instance = instance(), + config = {0, gen_random_list_of_pco()} }. gen_v2_absolute_time_of_mbms_data_transfer() -> @@ -2135,32 +2302,58 @@ gen_v2_absolute_time_of_mbms_data_transfer() -> gen_v2_henb_information_reporting_() -> #v2_henb_information_reporting_{ - instance = instance() + instance = instance(), + flags = flags(['FTI']) }. gen_v2_ipv4_configuration_parameters() -> #v2_ipv4_configuration_parameters{ - instance = instance() + instance = instance(), + prefix_length = integer(0,32), + default_route = ip4_address() }. gen_v2_change_to_report_flags_() -> #v2_change_to_report_flags_{ - instance = instance() - }. + instance = instance(), + flags = flags(['TZCR', 'SNCR']) + }. gen_v2_action_indication() -> #v2_action_indication{ - instance = instance() + instance = instance(), + indication = integer(0,7) }. gen_v2_twan_identifier() -> - #v2_twan_identifier{ - instance = instance() - }. + oneof( + [#v2_twan_identifier{ + instance = instance(), + ssid = binary(), + bssid = oneof([undefined, binary(6)]), + civic_address = oneof([undefined, binary()]), + plmn_id = oneof([undefined, {mcc(), mnc()}]), + operator_name = oneof([undefined, binary()]), + relay_identity_type = undefined, + relay_identity = undefined, + circuit_id = undefined + }, + #v2_twan_identifier{ + instance = instance(), + ssid = binary(), + bssid = oneof([undefined, binary(6)]), + civic_address = oneof([undefined, binary()]), + plmn_id = oneof([undefined, {mcc(), mnc()}]), + operator_name = oneof([undefined, binary()]), + relay_identity_type = uint8(), + relay_identity = binary(), + circuit_id = binary() + }]). gen_v2_uli_timestamp() -> #v2_uli_timestamp{ - instance = instance() + instance = instance(), + timestamp = uint32() }. gen_v2_mbms_flags() -> @@ -2170,27 +2363,35 @@ gen_v2_mbms_flags() -> gen_v2_ran_nas_cause() -> #v2_ran_nas_cause{ - instance = instance() - }. + instance = instance(), + protocol = uint4(), + type = uint4(), + cause = binary() + }. gen_v2_cn_operator_selection_entity() -> #v2_cn_operator_selection_entity{ - instance = instance() + instance = instance(), + entity = integer(0,3) }. gen_v2_trusted_wlan_mode_indication() -> #v2_trusted_wlan_mode_indication{ - instance = instance() + instance = instance(), + indication = flags(['MCM', 'SCM']) }. gen_v2_node_number() -> #v2_node_number{ - instance = instance() + instance = instance(), + number = binary() }. gen_v2_node_identifier() -> #v2_node_identifier{ - instance = instance() + instance = instance(), + name = binary(), + realm = binary() }. gen_v2_presence_reporting_area_action() -> @@ -2205,37 +2406,45 @@ gen_v2_presence_reporting_area_information() -> gen_v2_twan_identifier_timestamp() -> #v2_twan_identifier_timestamp{ - instance = instance() + instance = instance(), + timestamp = uint32() }. gen_v2_overload_control_information() -> #v2_overload_control_information{ - instance = instance() + instance = instance(), + group = v2_ie_group() }. gen_v2_load_control_information() -> #v2_load_control_information{ - instance = instance() + instance = instance(), + group = v2_ie_group() }. gen_v2_metric() -> #v2_metric{ - instance = instance() + instance = instance(), + value = uint8() }. gen_v2_sequence_number() -> #v2_sequence_number{ - instance = instance() + instance = instance(), + value = uint32() }. gen_v2_apn_and_relative_capacity() -> #v2_apn_and_relative_capacity{ - instance = instance() + instance = instance(), + capacity = uint8(), + apn = binary() }. gen_v2_wlan_offloadability_indication() -> #v2_wlan_offloadability_indication{ - instance = instance() + instance = instance(), + indication = flags(['EUTRAN', 'UTRAN']) }. gen_v2_private_extension() ->