diff --git a/doc/nas_eps.org b/doc/nas_eps.org index 475706e..3004488 100644 --- a/doc/nas_eps.org +++ b/doc/nas_eps.org @@ -186,14 +186,17 @@ *** 8.2.11.2 Detach request UE terminated detach - | IEI | Information Element | Type/Reference | Presence | Format | Length | - |-----+---------------------------------+----------------------------+----------+--------+--------| - | | Protocol discriminator | Protocol discriminator 9.2 | M | V | 1/2 | - | | Security header type | Security header type 9.3.1 | M | V | 1/2 | - | | Detach request message identity | Message type 9.8 | M | V | 1 | - | | Detach type | Detach type 9.9.3.7 | M | V | 1/2 | - | | Spare half octet | Spare half octet 9.9.2.9 | M | V | 1/2 | - | 53 | EMM cause | EMM cause 9.9.3.9 | O | TV | 2 | + | IEI | Information Element | Type/Reference | Presence | Format | Length | + |-----+---------------------------------+--------------------------------------+----------+--------+--------| + | | Protocol discriminator | Protocol discriminator 9.2 | M | V | 1/2 | + | | Security header type | Security header type 9.3.1 | M | V | 1/2 | + | | Detach request message identity | Message type 9.8 | M | V | 1 | + | | Detach type | Detach type 9.9.3.7 | M | V | 1/2 | + | | Spare half octet | Spare half octet 9.9.2.9 | M | V | 1/2 | + | 53 | EMM cause | EMM cause 9.9.3.9 | O | TV | 2 | + | 1C | Lower bound timer value | GPRS timer 3 9.9.3.16B | O | TLV | 3 | + | 1D | forbidden roaming list | Tracking area identity list 9.9.3.33 | O | TLV | 9-98 | + | 1E | forbidden provision list | Tracking area identity list 9.9.3.33 | O | TLV | 9-98 | *** 8.2.12 Downlink NAS Transport diff --git a/src/otc_nas_eps_emm.erl b/src/otc_nas_eps_emm.erl index 8e0c1d2..821563b 100644 --- a/src/otc_nas_eps_emm.erl +++ b/src/otc_nas_eps_emm.erl @@ -10,37 +10,43 @@ spec() -> "3GPP TS 24.301 version 16.8.0". -codec({SecurityHeaderType, Bin}, _Opts) when is_atom(SecurityHeaderType), is_binary(Bin) -> - decode({SecurityHeaderType, Bin}); -codec(Map, _Opts) when is_map(Map) -> - encode({Map, <<>>}); -codec({Map, PDU}, _Opts) when is_map(Map) -> - encode({Map, PDU}). +codec({SecurityHeaderType, Bin}, Opts) when is_atom(SecurityHeaderType), is_binary(Bin) -> + decode({SecurityHeaderType, Bin}, Opts); +codec(Map, Opts) when is_map(Map) -> + encode({Map, <<>>}, Opts); +codec({Map, PDU}, Opts) when is_map(Map) -> + encode({Map, PDU}, Opts). next(_) -> {ok, nas_eps}. -decode({plain_nas_message, <>}) -> +decode(V) -> + decode(V, #{}). + +decode({plain_nas_message, <>}, Opts) -> MsgType = otc_nas_eps:parse_msg_type(MT), - Msg = decode_emm_msg(MsgType, OIE), + Msg = decode_emm_msg(MsgType, OIE, Opts), Msg#{message_type => MsgType}; -decode({service_request, Bin}) -> - Msg = decode_emm_msg(service_request, Bin), +decode({service_request, Bin}, Opts) -> + Msg = decode_emm_msg(service_request, Bin, Opts), Msg#{message_type => service_request}; -decode({_SHT, <>}) -> +decode({_SHT, <>}, _Opts) -> {#{message_authentication_code => MAC, sequence_number => SN }, NMSG}. -encode({#{message_authentication_code := MAC, sequence_number := SN}, NMSG}) -> +encode(V) -> + encode(V, #{}). + +encode({#{message_authentication_code := MAC, sequence_number := SN}, NMSG}, _Opts) -> <>; -encode({#{message_type := service_request} = Msg, _}) -> - encode_emm_msg(service_request, Msg); -encode({#{message_type := MsgType} = Msg, _}) -> - Bin = encode_emm_msg(MsgType, Msg), +encode({#{message_type := service_request} = Msg, _}, Opts) -> + encode_emm_msg(service_request, Msg, Opts); +encode({#{message_type := MsgType} = Msg, _}, Opts) -> + Bin = encode_emm_msg(MsgType, Msg, Opts), MT = otc_nas_eps:compose_msg_type(MsgType), <>. -decode_emm_msg(attach_accept, Bin0) -> +decode_emm_msg(attach_accept, Bin0, _Opts) -> {_, Bin1} = otc_l3_codec:decode_v(Bin0, half), {EpsAttachResult, Bin2} = otc_l3_codec:decode_v(Bin1, half), {T3412Value, Bin3} = otc_l3_codec:decode_v(Bin2, 1), @@ -77,13 +83,13 @@ decode_emm_msg(attach_accept, Bin0) -> tai_list => TaiList, esm_message_container => EsmMessageContainer }; -decode_emm_msg(attach_complete, Bin0) -> +decode_emm_msg(attach_complete, Bin0, _Opts) -> {EsmMessageContainer, Bin1} = otc_l3_codec:decode_lve(Bin0), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{esm_message_container => EsmMessageContainer }; -decode_emm_msg(attach_reject, Bin0) -> +decode_emm_msg(attach_reject, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [{esm_message_container, 16#78, tlve, {6, n}}, {t3346_value, 16#5F, tlv, 3}, @@ -92,7 +98,7 @@ decode_emm_msg(attach_reject, Bin0) -> {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(attach_request, Bin0) -> +decode_emm_msg(attach_request, Bin0, _Opts) -> {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {EpsAttachType, Bin2} = otc_l3_codec:decode_v(Bin1, half), {EpsMobileIdentity, Bin3} = otc_l3_codec:decode_lv(Bin2), @@ -131,17 +137,17 @@ decode_emm_msg(attach_request, Bin0) -> ue_network_capability => UeNetworkCapability, esm_message_container => EsmMessageContainer }; -decode_emm_msg(authentication_failure, Bin0) -> +decode_emm_msg(authentication_failure, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [{authentication_failure_parameter, 16#30, tlv, 16}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(authentication_reject, Bin0) -> +decode_emm_msg(authentication_reject, Bin0, _Opts) -> Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(authentication_request, Bin0) -> +decode_emm_msg(authentication_request, Bin0, _Opts) -> {_, Bin1} = otc_l3_codec:decode_v(Bin0, half), {NasKeySetIdentifierasme, Bin2} = otc_l3_codec:decode_v(Bin1, half), {AuthenticationParameterRandEpsChallenge, Bin3} = otc_l3_codec:decode_v(Bin2, 16), @@ -152,13 +158,13 @@ decode_emm_msg(authentication_request, Bin0) -> authentication_parameter_rand_eps_challenge => AuthenticationParameterRandEpsChallenge, authentication_parameter_autn_eps_challenge => AuthenticationParameterAutnEpsChallenge }; -decode_emm_msg(authentication_response, Bin0) -> +decode_emm_msg(authentication_response, Bin0, _Opts) -> {AuthenticationResponseParameter, Bin1} = otc_l3_codec:decode_lv(Bin0), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{authentication_response_parameter => AuthenticationResponseParameter }; -decode_emm_msg(cs_service_notification, Bin0) -> +decode_emm_msg(cs_service_notification, Bin0, _Opts) -> {PagingIdentity, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [{cli, 16#60, tlv, {3, 14}}, {ss_code, 16#61, tv, 2}, @@ -167,38 +173,84 @@ decode_emm_msg(cs_service_notification, Bin0) -> {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{paging_identity => PagingIdentity }; -decode_emm_msg(detach_accept_ue_originating_detach, Bin0) -> - Opts = [], - {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), - Optionals; -decode_emm_msg(detach_accept_ue_terminated_detach, Bin0) -> +decode_emm_msg(detach_accept, Bin0, _Opts) -> Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(detach_request_ue_originating_detach, Bin0) -> +decode_emm_msg(detach_request, Bin0, #{direction := 'id-downlinkNASTransport'}) -> + %% UE terminated + {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), + {DetachType, Bin2} = otc_l3_codec:decode_v(Bin1, half), + Opts = [{emm_cause, 16#53, tv, 2}, + {lower_bound_timer_value, 16#1C, tlv, 3}, + {forbidden_roaming_list, 16#1D, tlv, {9, 98}}, + {forbidden_provision_list, 16#1E, tlv, {9, 98}} + ], + {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin2, Opts), + Optionals#{direction => ue_terminated, + detach_type => DetachType, + nas_key_set_identifier => NasKeySetIdentifier}; +decode_emm_msg(detach_request, Bin0, #{direction := 'id-uplinkNASTransport'}) -> + %% UE originating {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {DetachType, Bin2} = otc_l3_codec:decode_v(Bin1, half), {EpsMobileIdentity, Bin3} = otc_l3_codec:decode_lv(Bin2), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin3, Opts), - Optionals#{detach_type => DetachType, + Optionals#{direction => ue_originated, + detach_type => DetachType, nas_key_set_identifier => NasKeySetIdentifier, - eps_mobile_identity => EpsMobileIdentity - }; -decode_emm_msg(detach_request_ue_terminated_detach, Bin0) -> - {_, Bin1} = otc_l3_codec:decode_v(Bin0, half), + eps_mobile_identity => EpsMobileIdentity}; +decode_emm_msg(detach_request, Bin0, _Opts) -> + %% This will be a bit weird: + %% DETACH REQUEST can come from either network or UE + %% 1. if it is UE originating detach, then it can only contain the + %% EPS mobile identity, which is mandatory, but + %% 2. if it is UE terminated detach, then there are optional fields for + %% - EMM cause, + %% - Lower bound timer value, + %% - TAI list containing forbidden tracking areas for roaming, + %% - TAI list containing forbidden tracking areas for regional + %% provision of service. + {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {DetachType, Bin2} = otc_l3_codec:decode_v(Bin1, half), - Opts = [{emm_cause, 16#53, tv, 2}], - {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin2, Opts), - Optionals#{detach_type => DetachType - }; -decode_emm_msg(downlink_nas_transport, Bin0) -> + Opts = [{emm_cause, 16#53, tv, 2}, + {lower_bound_timer_value, 16#1C, tlv, 3}, + {forbidden_roaming_list, 16#1D, tlv, {9, 98}}, + {forbidden_provision_list, 16#1E, tlv, {9, 98}} + ], + {Optionals, Unknown0} = otc_l3_codec:decode_iei_list(Bin2, Opts), + case {map_size(Optionals) > 0, byte_size(Unknown0) > 0} of + {false, true} -> + %% UE originating detach + {EpsMobileIdentity, _} = otc_l3_codec:decode_lv(Unknown0), + #{direction => ue_originated, + detach_type => DetachType, + nas_key_set_identifier => NasKeySetIdentifier, + eps_mobile_identity => EpsMobileIdentity}; + {false, false} -> + %% No clue; say it's UE terminated detach without any optionals + Optionals#{direction => ue_terminated, + detach_type => DetachType, + nas_key_set_identifier => NasKeySetIdentifier}; + {true, false} -> + %% UE terminated detach + Optionals#{direction => ue_terminated, + detach_type => DetachType, + nas_key_set_identifier => NasKeySetIdentifier}; + {true, true} -> + %% No clue; say it's UE terminated detach with unknown optionals + Optionals#{direction => ue_terminated, + detach_type => DetachType, + nas_key_set_identifier => NasKeySetIdentifier} + end; +decode_emm_msg(downlink_nas_transport, Bin0, _Opts) -> {NasMessageContainer, Bin1} = otc_l3_codec:decode_lv(Bin0), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{nas_message_container => NasMessageContainer }; -decode_emm_msg(emm_information, Bin0) -> +decode_emm_msg(emm_information, Bin0, _Opts) -> Opts = [{full_name_for_network, 16#43, tlv, {3, n}}, {short_name_for_network, 16#45, tlv, {3, n}}, {local_time_zone, 16#46, tv, 2}, @@ -206,13 +258,13 @@ decode_emm_msg(emm_information, Bin0) -> {network_daylight_saving_time, 16#49, tlv, 3}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(emm_status, Bin0) -> +decode_emm_msg(emm_status, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(extended_service_request, Bin0) -> +decode_emm_msg(extended_service_request, Bin0, _Opts) -> {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {ServiceType, Bin2} = otc_l3_codec:decode_v(Bin1, half), {MTmsi, Bin3} = otc_l3_codec:decode_lv(Bin2), @@ -223,7 +275,7 @@ decode_emm_msg(extended_service_request, Bin0) -> nas_key_set_identifier => NasKeySetIdentifier, m_tmsi => MTmsi }; -decode_emm_msg(guti_reallocation_command, Bin0) -> +decode_emm_msg(guti_reallocation_command, Bin0, _Opts) -> {Guti, Bin1} = otc_l3_codec:decode_lv(Bin0), Opts = [{tai_list, 16#54, tlv, {8, 98}}, {dcn_id, 16#65, tlv, 4}, @@ -232,18 +284,18 @@ decode_emm_msg(guti_reallocation_command, Bin0) -> {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{guti => Guti }; -decode_emm_msg(guti_reallocation_complete, Bin0) -> +decode_emm_msg(guti_reallocation_complete, Bin0, _Opts) -> Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(identity_request, Bin0) -> +decode_emm_msg(identity_request, Bin0, _Opts) -> {_, Bin1} = otc_l3_codec:decode_v(Bin0, half), {IdentityType, Bin2} = otc_l3_codec:decode_v(Bin1, half), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin2, Opts), Optionals#{identity_type => IdentityType }; -decode_emm_msg(identity_response, Bin0) -> +decode_emm_msg(identity_response, Bin0, _Opts) -> {IdentityResponseMessage, Bin1} = otc_l3_codec:decode_v(Bin0, 1), {MobileIdentity, Bin2} = otc_l3_codec:decode_lv(Bin1), Opts = [], @@ -251,7 +303,7 @@ decode_emm_msg(identity_response, Bin0) -> Optionals#{identity_response_message => IdentityResponseMessage, mobile_identity => MobileIdentity }; -decode_emm_msg(security_mode_command, Bin0) -> +decode_emm_msg(security_mode_command, Bin0, _Opts) -> {SelectedNasSecurityAlgorithms, Bin1} = otc_l3_codec:decode_v(Bin0, 1), {_, Bin2} = otc_l3_codec:decode_v(Bin1, half), {NasKeySetIdentifier, Bin3} = otc_l3_codec:decode_v(Bin2, half), @@ -267,19 +319,19 @@ decode_emm_msg(security_mode_command, Bin0) -> nas_key_set_identifier => NasKeySetIdentifier, replayed_ue_security_capabilities => ReplayedUeSecurityCapabilities }; -decode_emm_msg(security_mode_complete, Bin0) -> +decode_emm_msg(security_mode_complete, Bin0, _Opts) -> Opts = [{imeisv, 16#23, tlv, 11}, {replayed_nas_message_container, 16#79, tlve, {3, n}}, {ue_radio_capability_id, 16#66, tlv, {3, n}}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(security_mode_reject, Bin0) -> +decode_emm_msg(security_mode_reject, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(security_protected_nas_message, Bin0) -> +decode_emm_msg(security_protected_nas_message, Bin0, _Opts) -> {MessageAuthenticationCode, Bin1} = otc_l3_codec:decode_v(Bin0, 4), {SequenceNumber, Bin2} = otc_l3_codec:decode_v(Bin1, 1), {NasMessage, Bin3} = otc_l3_codec:decode_v(Bin2, {1, n}), @@ -289,14 +341,14 @@ decode_emm_msg(security_protected_nas_message, Bin0) -> sequence_number => SequenceNumber, nas_message => NasMessage }; -decode_emm_msg(service_reject, Bin0) -> +decode_emm_msg(service_reject, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [{t3346_value, 16#5F, tlv, 3}, {t3448_value, 16#6B, tlv, 3}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(service_request, Bin0) -> +decode_emm_msg(service_request, Bin0, _Opts) -> {KsiAndSequenceNumber, Bin1} = otc_l3_codec:decode_v(Bin0, 1), {MessageAuthenticationCodeShort, Bin2} = otc_l3_codec:decode_v(Bin1, 2), Opts = [], @@ -304,7 +356,7 @@ decode_emm_msg(service_request, Bin0) -> Optionals#{ksi_and_sequence_number => KsiAndSequenceNumber, message_authentication_code_short => MessageAuthenticationCodeShort }; -decode_emm_msg(tracking_area_update_accept, Bin0) -> +decode_emm_msg(tracking_area_update_accept, Bin0, _Opts) -> {_, Bin1} = otc_l3_codec:decode_v(Bin0, half), {EpsUpdateResult, Bin2} = otc_l3_codec:decode_v(Bin1, half), Opts = [{t3412_value, 16#5A, tv, 2}, @@ -339,18 +391,18 @@ decode_emm_msg(tracking_area_update_accept, Bin0) -> {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin2, Opts), Optionals#{eps_update_result => EpsUpdateResult }; -decode_emm_msg(tracking_area_update_complete, Bin0) -> +decode_emm_msg(tracking_area_update_complete, Bin0, _Opts) -> Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), Optionals; -decode_emm_msg(tracking_area_update_reject, Bin0) -> +decode_emm_msg(tracking_area_update_reject, Bin0, _Opts) -> {EmmCause, Bin1} = otc_l3_codec:decode_v(Bin0, 1), Opts = [{t3346_value, 16#5F, tlv, 3}, {extended_emm_cause, 16#A, tv, 1}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{emm_cause => EmmCause }; -decode_emm_msg(tracking_area_update_request, Bin0) -> +decode_emm_msg(tracking_area_update_request, Bin0, _Opts) -> {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {EpsUpdateType, Bin2} = otc_l3_codec:decode_v(Bin1, half), {OldGuti, Bin3} = otc_l3_codec:decode_lv(Bin2), @@ -391,13 +443,13 @@ decode_emm_msg(tracking_area_update_request, Bin0) -> nas_key_set_identifier => NasKeySetIdentifier, old_guti => OldGuti }; -decode_emm_msg(uplink_nas_transport, Bin0) -> +decode_emm_msg(uplink_nas_transport, Bin0, _Opts) -> {NasMessageContainer, Bin1} = otc_l3_codec:decode_lv(Bin0), Opts = [], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin1, Opts), Optionals#{nas_message_container => NasMessageContainer }; -decode_emm_msg(downlink_generic_nas_transport, Bin0) -> +decode_emm_msg(downlink_generic_nas_transport, Bin0, _Opts) -> {GenericMessageContainerType, Bin1} = otc_l3_codec:decode_v(Bin0, 1), {GenericMessageContainer, Bin2} = otc_l3_codec:decode_lve(Bin1), Opts = [{additional_information, 16#65, tlv, {3, n}}], @@ -405,7 +457,7 @@ decode_emm_msg(downlink_generic_nas_transport, Bin0) -> Optionals#{generic_message_container_type => GenericMessageContainerType, generic_message_container => GenericMessageContainer }; -decode_emm_msg(uplink_generic_nas_transport, Bin0) -> +decode_emm_msg(uplink_generic_nas_transport, Bin0, _Opts) -> {GenericMessageContainerType, Bin1} = otc_l3_codec:decode_v(Bin0, 1), {GenericMessageContainer, Bin2} = otc_l3_codec:decode_lve(Bin1), Opts = [{additional_information, 16#65, tlv, {3, n}}], @@ -413,7 +465,7 @@ decode_emm_msg(uplink_generic_nas_transport, Bin0) -> Optionals#{generic_message_container_type => GenericMessageContainerType, generic_message_container => GenericMessageContainer }; -decode_emm_msg(control_plane_service_request, Bin0) -> +decode_emm_msg(control_plane_service_request, Bin0, _Opts) -> {NasKeySetIdentifier, Bin1} = otc_l3_codec:decode_v(Bin0, half), {ControlPlaneServiceType, Bin2} = otc_l3_codec:decode_v(Bin1, half), Opts = [{esm_message_container, 16#78, tlve, {3, n}}, @@ -424,7 +476,7 @@ decode_emm_msg(control_plane_service_request, Bin0) -> Optionals#{control_plane_service_type => ControlPlaneServiceType, nas_key_set_identifier => NasKeySetIdentifier }; -decode_emm_msg(service_accept, Bin0) -> +decode_emm_msg(service_accept, Bin0, _Opts) -> Opts = [{eps_bearer_context_status, 16#57, tlv, 4}, {t3448_value, 16#6B, tlv, 3}], {Optionals, _Unknown} = otc_l3_codec:decode_iei_list(Bin0, Opts), @@ -433,7 +485,7 @@ decode_emm_msg(service_accept, Bin0) -> encode_emm_msg(attach_accept, #{eps_attach_result := EpsAttachResult, t3412_value := T3412Value, tai_list := TaiList, - esm_message_container := EsmMessageContainer} = Msg) -> + esm_message_container := EsmMessageContainer} = Msg, _Opts) -> Bin1 = <<0:4>>, % spare_half_octet Bin2 = otc_l3_codec:encode_v(EpsAttachResult, half, <<>>), Bin3 = otc_l3_codec:encode_v(T3412Value, 1, <<>>), @@ -466,12 +518,12 @@ encode_emm_msg(attach_accept, #{eps_attach_result := EpsAttachResult, {negotiated_drx_parameter_in_nb_s1_mode, 16#36, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(attach_complete, #{esm_message_container := EsmMessageContainer} = Msg) -> +encode_emm_msg(attach_complete, #{esm_message_container := EsmMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_lve(EsmMessageContainer, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(attach_reject, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(attach_reject, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [{esm_message_container, 16#78, tlve, {6, n}}, {t3346_value, 16#5F, tlv, 3}, @@ -483,7 +535,7 @@ encode_emm_msg(attach_request, #{eps_attach_type := EpsAttachType, nas_key_set_identifier := NasKeySetIdentifier, eps_mobile_identity := EpsMobileIdentity, ue_network_capability := UeNetworkCapability, - esm_message_container := EsmMessageContainer} = Msg) -> + esm_message_container := EsmMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), Bin2 = otc_l3_codec:encode_v(EpsAttachType, half, <<>>), Bin3 = otc_l3_codec:encode_lv(EpsMobileIdentity, <<>>), @@ -517,18 +569,18 @@ encode_emm_msg(attach_request, #{eps_attach_type := EpsAttachType, {drx_parameter_in_nb_s1_mode, 16#36, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(authentication_failure, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(authentication_failure, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [{authentication_failure_parameter, 16#30, tlv, 16}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(authentication_reject, #{} = Msg) -> +encode_emm_msg(authentication_reject, #{} = Msg, _Opts) -> Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; encode_emm_msg(authentication_request, #{nas_key_set_identifierasme := NasKeySetIdentifierasme, authentication_parameter_rand_eps_challenge := AuthenticationParameterRandEpsChallenge, - authentication_parameter_autn_eps_challenge := AuthenticationParameterAutnEpsChallenge} = Msg) -> + authentication_parameter_autn_eps_challenge := AuthenticationParameterAutnEpsChallenge} = Msg, _Opts) -> Bin1 = <<0:4>>, % spare_half_octet Bin2 = otc_l3_codec:encode_v(NasKeySetIdentifierasme, half, <<>>), Bin3 = otc_l3_codec:encode_v(AuthenticationParameterRandEpsChallenge, 16, <<>>), @@ -536,12 +588,12 @@ encode_emm_msg(authentication_request, #{nas_key_set_identifierasme := NasKeySet Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(authentication_response, #{authentication_response_parameter := AuthenticationResponseParameter} = Msg) -> +encode_emm_msg(authentication_response, #{authentication_response_parameter := AuthenticationResponseParameter} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_lv(AuthenticationResponseParameter, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(cs_service_notification, #{paging_identity := PagingIdentity} = Msg) -> +encode_emm_msg(cs_service_notification, #{paging_identity := PagingIdentity} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(PagingIdentity, 1, <<>>), Opts = [{cli, 16#60, tlv, {3, 14}}, {ss_code, 16#61, tv, 2}, @@ -549,35 +601,35 @@ encode_emm_msg(cs_service_notification, #{paging_identity := PagingIdentity} = M {lcs_client_identity, 16#63, tlv, {3, 257}}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(detach_accept_ue_originating_detach, #{} = Msg) -> +encode_emm_msg(detach_accept, #{} = Msg, _Opts) -> Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; -encode_emm_msg(detach_accept_ue_terminated_detach, #{} = Msg) -> - Opts = [], - OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), - OptBin; -encode_emm_msg(detach_request_ue_originating_detach, #{detach_type := DetachType, - nas_key_set_identifier := NasKeySetIdentifier, - eps_mobile_identity := EpsMobileIdentity} = Msg) -> +encode_emm_msg(detach_request, #{detach_type := DetachType, + nas_key_set_identifier := NasKeySetIdentifier, + eps_mobile_identity := EpsMobileIdentity} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), Bin2 = otc_l3_codec:encode_v(DetachType, half, <<>>), Bin3 = otc_l3_codec:encode_lv(EpsMobileIdentity, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(detach_request_ue_terminated_detach, #{detach_type := DetachType} = Msg) -> +encode_emm_msg(detach_request, #{detach_type := DetachType} = Msg, _Opts) -> Bin1 = <<0:4>>, % spare_half_octet Bin2 = otc_l3_codec:encode_v(DetachType, half, <<>>), - Opts = [{emm_cause, 16#53, tv, 2}], + Opts = [{emm_cause, 16#53, tv, 2}, + {lower_bound_timer_value, 16#1C, tlv, 3}, + {forbidden_roaming_list, 16#1D, tlv, {9, 98}}, + {forbidden_provision_list, 16#1E, tlv, {9, 98}} + ], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(downlink_nas_transport, #{nas_message_container := NasMessageContainer} = Msg) -> +encode_emm_msg(downlink_nas_transport, #{nas_message_container := NasMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_lv(NasMessageContainer, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(emm_information, #{} = Msg) -> +encode_emm_msg(emm_information, #{} = Msg, _Opts) -> Opts = [{full_name_for_network, 16#43, tlv, {3, n}}, {short_name_for_network, 16#45, tlv, {3, n}}, {local_time_zone, 16#46, tv, 2}, @@ -585,14 +637,14 @@ encode_emm_msg(emm_information, #{} = Msg) -> {network_daylight_saving_time, 16#49, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; -encode_emm_msg(emm_status, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(emm_status, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(extended_service_request, #{service_type := ServiceType, nas_key_set_identifier := NasKeySetIdentifier, - m_tmsi := MTmsi} = Msg) -> + m_tmsi := MTmsi} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), Bin2 = otc_l3_codec:encode_v(ServiceType, half, <<>>), Bin3 = otc_l3_codec:encode_lv(MTmsi, <<>>), @@ -600,7 +652,7 @@ encode_emm_msg(extended_service_request, #{service_type := ServiceType, {device_properties, 16#D, tv, 1}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(guti_reallocation_command, #{guti := Guti} = Msg) -> +encode_emm_msg(guti_reallocation_command, #{guti := Guti} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_lv(Guti, <<>>), Opts = [{tai_list, 16#54, tlv, {8, 98}}, {dcn_id, 16#65, tlv, 4}, @@ -608,18 +660,18 @@ encode_emm_msg(guti_reallocation_command, #{guti := Guti} = Msg) -> {ue_radio_capability_id_deletion_indication, 16#B, tv, 1}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(guti_reallocation_complete, #{} = Msg) -> +encode_emm_msg(guti_reallocation_complete, #{} = Msg, _Opts) -> Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; -encode_emm_msg(identity_request, #{identity_type := IdentityType} = Msg) -> +encode_emm_msg(identity_request, #{identity_type := IdentityType} = Msg, _Opts) -> Bin1 = <<0:4>>, % spare_half_octet Bin2 = otc_l3_codec:encode_v(IdentityType, half, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(identity_response, #{identity_response_message := IdentityResponseMessage, - mobile_identity := MobileIdentity} = Msg) -> + mobile_identity := MobileIdentity} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(IdentityResponseMessage, 1, <<>>), Bin2 = otc_l3_codec:encode_lv(MobileIdentity, <<>>), Opts = [], @@ -627,7 +679,7 @@ encode_emm_msg(identity_response, #{identity_response_message := IdentityRespons <>; encode_emm_msg(security_mode_command, #{selected_nas_security_algorithms := SelectedNasSecurityAlgorithms, nas_key_set_identifier := NasKeySetIdentifier, - replayed_ue_security_capabilities := ReplayedUeSecurityCapabilities} = Msg) -> + replayed_ue_security_capabilities := ReplayedUeSecurityCapabilities} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(SelectedNasSecurityAlgorithms, 1, <<>>), Bin2 = <<0:4>>, % spare_half_octet Bin3 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), @@ -640,40 +692,40 @@ encode_emm_msg(security_mode_command, #{selected_nas_security_algorithms := Sele {ue_radio_capability_id_request, 16#37, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(security_mode_complete, #{} = Msg) -> +encode_emm_msg(security_mode_complete, #{} = Msg, _Opts) -> Opts = [{imeisv, 16#23, tlv, 11}, {replayed_nas_message_container, 16#79, tlve, {3, n}}, {ue_radio_capability_id, 16#66, tlv, {3, n}}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; -encode_emm_msg(security_mode_reject, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(security_mode_reject, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(security_protected_nas_message, #{message_authentication_code := MessageAuthenticationCode, sequence_number := SequenceNumber, - nas_message := NasMessage} = Msg) -> + nas_message := NasMessage} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(MessageAuthenticationCode, 4, <<>>), Bin2 = otc_l3_codec:encode_v(SequenceNumber, 1, <<>>), Bin3 = otc_l3_codec:encode_v(NasMessage, {1, n}, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(service_reject, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(service_reject, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [{t3346_value, 16#5F, tlv, 3}, {t3448_value, 16#6B, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(service_request, #{ksi_and_sequence_number := KsiAndSequenceNumber, - message_authentication_code_short := MessageAuthenticationCodeShort} = Msg) -> + message_authentication_code_short := MessageAuthenticationCodeShort} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(KsiAndSequenceNumber, 1, <<>>), Bin2 = otc_l3_codec:encode_v(MessageAuthenticationCodeShort, 2, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(tracking_area_update_accept, #{eps_update_result := EpsUpdateResult} = Msg) -> +encode_emm_msg(tracking_area_update_accept, #{eps_update_result := EpsUpdateResult} = Msg, _Opts) -> Bin1 = <<0:4>>, % spare_half_octet Bin2 = otc_l3_codec:encode_v(EpsUpdateResult, half, <<>>), Opts = [{t3412_value, 16#5A, tv, 2}, @@ -707,11 +759,11 @@ encode_emm_msg(tracking_area_update_accept, #{eps_update_result := EpsUpdateResu {negotiated_drx_parameter_in_nb_s1_mode, 16#36, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(tracking_area_update_complete, #{} = Msg) -> +encode_emm_msg(tracking_area_update_complete, #{} = Msg, _Opts) -> Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), OptBin; -encode_emm_msg(tracking_area_update_reject, #{emm_cause := EmmCause} = Msg) -> +encode_emm_msg(tracking_area_update_reject, #{emm_cause := EmmCause} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(EmmCause, 1, <<>>), Opts = [{t3346_value, 16#5F, tlv, 3}, {extended_emm_cause, 16#A, tv, 1}], @@ -719,7 +771,7 @@ encode_emm_msg(tracking_area_update_reject, #{emm_cause := EmmCause} = Msg) -> <>; encode_emm_msg(tracking_area_update_request, #{eps_update_type := EpsUpdateType, nas_key_set_identifier := NasKeySetIdentifier, - old_guti := OldGuti} = Msg) -> + old_guti := OldGuti} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), Bin2 = otc_l3_codec:encode_v(EpsUpdateType, half, <<>>), Bin3 = otc_l3_codec:encode_lv(OldGuti, <<>>), @@ -757,27 +809,27 @@ encode_emm_msg(tracking_area_update_request, #{eps_update_type := EpsUpdateType, {drx_parameter_in_nb_s1_mode, 16#36, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(uplink_nas_transport, #{nas_message_container := NasMessageContainer} = Msg) -> +encode_emm_msg(uplink_nas_transport, #{nas_message_container := NasMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_lv(NasMessageContainer, <<>>), Opts = [], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(downlink_generic_nas_transport, #{generic_message_container_type := GenericMessageContainerType, - generic_message_container := GenericMessageContainer} = Msg) -> + generic_message_container := GenericMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(GenericMessageContainerType, 1, <<>>), Bin2 = otc_l3_codec:encode_lve(GenericMessageContainer, <<>>), Opts = [{additional_information, 16#65, tlv, {3, n}}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(uplink_generic_nas_transport, #{generic_message_container_type := GenericMessageContainerType, - generic_message_container := GenericMessageContainer} = Msg) -> + generic_message_container := GenericMessageContainer} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(GenericMessageContainerType, 1, <<>>), Bin2 = otc_l3_codec:encode_lve(GenericMessageContainer, <<>>), Opts = [{additional_information, 16#65, tlv, {3, n}}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; encode_emm_msg(control_plane_service_request, #{control_plane_service_type := ControlPlaneServiceType, - nas_key_set_identifier := NasKeySetIdentifier} = Msg) -> + nas_key_set_identifier := NasKeySetIdentifier} = Msg, _Opts) -> Bin1 = otc_l3_codec:encode_v(NasKeySetIdentifier, half, <<>>), Bin2 = otc_l3_codec:encode_v(ControlPlaneServiceType, half, <<>>), Opts = [{esm_message_container, 16#78, tlve, {3, n}}, @@ -786,7 +838,7 @@ encode_emm_msg(control_plane_service_request, #{control_plane_service_type := Co {device_properties, 16#D, tv, 1}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), <>; -encode_emm_msg(service_accept, #{} = Msg) -> +encode_emm_msg(service_accept, #{} = Msg, _Opts) -> Opts = [{eps_bearer_context_status, 16#57, tlv, 4}, {t3448_value, 16#6B, tlv, 3}], OptBin = otc_l3_codec:encode_iei_list(Msg, Opts), diff --git a/test/otc_nas_eps_codec_tests.erl b/test/otc_nas_eps_codec_tests.erl index 1a8154d..2b76b9f 100644 --- a/test/otc_nas_eps_codec_tests.erl +++ b/test/otc_nas_eps_codec_tests.erl @@ -3,7 +3,7 @@ -include_lib("eunit/include/eunit.hrl"). plain_attach_request_test_() -> - Bin = hexstream_to_binary(<<"0741710809101000001000100620200000000000040201d011">>), + Bin = binary:decode_hex(<<"0741710809101000001000100620200000000000040201d011">>), Map1 = #{protocol => nas_eps, security_header_type => plain_nas_message, protocol_discriminator => eps_mobility_management_messages}, @@ -31,20 +31,20 @@ plain_attach_request_test_() -> ]. integrity_attach_request_test_() -> - Bin = hexstream_to_binary(<<"17be27ab2e3a0741610bf644f05180000ac0000c0305f" - "070c0401100270233d011d12720808021100100001081" - "0600000000830600000000000d00000a00000500001000" - "5244f05100015c0a003103e5e03e11034f18a640080402" - "600000021f005d0103e0c1">>), - Bin2 = hexstream_to_binary(<<"0233d011d12720808021100100001081" - "0600000000830600000000000d00000a00000500001000" - >>), + Bin = binary:decode_hex(<<"17be27ab2e3a0741610bf644f05180000ac0000c0305f" + "070c0401100270233d011d12720808021100100001081" + "0600000000830600000000000d00000a00000500001000" + "5244f05100015c0a003103e5e03e11034f18a640080402" + "600000021f005d0103e0c1">>), + Bin2 = binary:decode_hex(<<"0233d011d12720808021100100001081" + "0600000000830600000000000d00000a00000500001000" + >>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected}, Map2 = #{protocol => nas_eps_emm, sequence_number => <<58>>, - message_authentication_code => hexstream_to_binary(<<"be27ab2e">>)}, + message_authentication_code => binary:decode_hex(<<"be27ab2e">>)}, Map3 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, @@ -85,8 +85,8 @@ integrity_attach_request_test_() -> ]. plain_authentication_request_test_() -> - Bin = hexstream_to_binary(<<"075206a73180283e95708d1c6141a545b68a" - "45100aa0a855812680002863ebdc835cec7c">>), + Bin = binary:decode_hex(<<"075206a73180283e95708d1c6141a545b68a" + "45100aa0a855812680002863ebdc835cec7c">>), Map1 = #{protocol => nas_eps, security_header_type => plain_nas_message, protocol_discriminator => eps_mobility_management_messages}, @@ -94,15 +94,15 @@ plain_authentication_request_test_() -> message_type => authentication_request, nas_key_set_identifierasme => 6, authentication_parameter_rand_eps_challenge => - hexstream_to_binary(<<"a73180283e95708d1c6141a545b68a45">>), + binary:decode_hex(<<"a73180283e95708d1c6141a545b68a45">>), authentication_parameter_autn_eps_challenge => - hexstream_to_binary(<<"0aa0a855812680002863ebdc835cec7c">>)}, + binary:decode_hex(<<"0aa0a855812680002863ebdc835cec7c">>)}, [?_assertEqual({ok, [Map1, Map2]}, otc:decode(nas_eps, Bin)), ?_assertEqual({ok, Bin}, otc:encode([Map1, Map2])) ]. plain_authentication_response_test_() -> - Bin = hexstream_to_binary(<<"17f908e12d3c075308373f4dcdb2e7769b">>), + Bin = binary:decode_hex(<<"17f908e12d3c075308373f4dcdb2e7769b">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected}, @@ -121,34 +121,34 @@ plain_authentication_response_test_() -> ]. security_mode_command_test_() -> - Bin = hexstream_to_binary(<<"37685cc2d900075d010605f070c04070">>), + Bin = binary:decode_hex(<<"37685cc2d900075d010605f070c04070">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_eps_security}, Map2 = #{protocol => nas_eps_emm, sequence_number => <<0>>, - message_authentication_code => hexstream_to_binary(<<"685cc2d9">>)}, + message_authentication_code => binary:decode_hex(<<"685cc2d9">>)}, Map3 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => plain_nas_message}, Map4 = #{protocol => nas_eps_emm, message_type => security_mode_command, nas_key_set_identifier => 6, - replayed_ue_security_capabilities => hexstream_to_binary(<<"f070c04070">>), + replayed_ue_security_capabilities => binary:decode_hex(<<"f070c04070">>), selected_nas_security_algorithms => <<1>>}, [?_assertEqual({ok, [Map1, Map2, Map3, Map4]}, otc:decode(nas_eps, Bin)), ?_assertEqual({ok, Bin}, otc:encode([Map1, Map2, Map3, Map4])) ]. security_mode_complete_test_() -> - Bin = hexstream_to_binary(<<"47cd4d049b00075e">>), + Bin = binary:decode_hex(<<"47cd4d049b00075e">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered_eps_security}, Map2 = #{protocol => nas_eps_emm, sequence_number => <<0>>, - message_authentication_code => hexstream_to_binary(<<"cd4d049b">>)}, + message_authentication_code => binary:decode_hex(<<"cd4d049b">>)}, Map3 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => plain_nas_message}, @@ -159,12 +159,12 @@ security_mode_complete_test_() -> ]. esm_information_request_test_() -> - Bin = hexstream_to_binary(<<"2745d8f29b010233d9">>), + Bin = binary:decode_hex(<<"2745d8f29b010233d9">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, Map2 = #{protocol => nas_eps_emm, - message_authentication_code => hexstream_to_binary(<<"45d8f29b0">>), + message_authentication_code => binary:decode_hex(<<"45d8f29b">>), sequence_number => <<1>>}, Map3 = #{protocol => nas_eps, eps_bearer_identity => 0, @@ -177,13 +177,13 @@ esm_information_request_test_() -> ]. esm_information_response_test_() -> - Bin = hexstream_to_binary(<<"270bef195a010233da280908696e7465726e6574">>), + Bin = binary:decode_hex(<<"270bef195a010233da280908696e7465726e6574">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, Map2 = #{protocol => nas_eps_emm, sequence_number => <<1>>, - message_authentication_code => hexstream_to_binary(<<"0bef195a">>)}, + message_authentication_code => binary:decode_hex(<<"0bef195a">>)}, Map3 = #{protocol => nas_eps, eps_bearer_identity => 0, protocol_discriminator => eps_session_management_messages}, @@ -196,19 +196,19 @@ esm_information_response_test_() -> ]. attach_accept_test_() -> - Bin = hexstream_to_binary(<<"27118d83930207420149062044f051000100725233c10" - "1091c08696e7465726e6574066d6e63303135066d6363" - "343430046770727305010a0802615d0100301023911f9" - "396fefe764bffff00f700f7003203843401005e04fefe" - "f7f7272780000d0401010101000d04010000018021100" - "300001081060101010183060100000100100205dc500b" - "f644f05180000ac0000e0359496401015e0106">>), - Bin3 = hexstream_to_binary(<<"5233c10" - "1091c08696e7465726e6574066d6e63303135066d6363" - "343430046770727305010a0802615d0100301023911f9" - "396fefe764bffff00f700f7003203843401005e04fefe" - "f7f7272780000d0401010101000d04010000018021100" - "300001081060101010183060100000100100205dc">>), + Bin = binary:decode_hex(<<"27118d83930207420149062044f051000100725233c10" + "1091c08696e7465726e6574066d6e63303135066d6363" + "343430046770727305010a0802615d0100301023911f9" + "396fefe764bffff00f700f7003203843401005e04fefe" + "f7f7272780000d0401010101000d04010000018021100" + "300001081060101010183060100000100100205dc500b" + "f644f05180000ac0000e0359496401015e0106">>), + Bin3 = binary:decode_hex(<<"5233c10" + "1091c08696e7465726e6574066d6e63303135066d6363" + "343430046770727305010a0802615d0100301023911f9" + "396fefe764bffff00f700f7003203843401005e04fefe" + "f7f7272780000d0401010101000d04010000018021100" + "300001081060101010183060100000100100205dc">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, @@ -258,8 +258,8 @@ attach_accept_test_() -> ]. activate_default_eps_bearer_context_accept_test_() -> - Bin = hexstream_to_binary(<<"2714573c4602074300035200c2">>), - Bin3 = hexstream_to_binary(<<"5200c2">>), + Bin = binary:decode_hex(<<"2714573c4602074300035200c2">>), + Bin3 = binary:decode_hex(<<"5200c2">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, @@ -287,9 +287,9 @@ activate_default_eps_bearer_context_accept_test_() -> ]. pdn_connectivity_request_test_() -> - Bin = hexstream_to_binary(<<"27ed17dacc030234d031280403696d732729808021100" - "1000010810600000000830600000000000d0000030000" - "0100000c00000a00000500001000">>), + Bin = binary:decode_hex(<<"27ed17dacc030234d031280403696d732729808021100" + "1000010810600000000830600000000000d0000030000" + "0100000c00000a00000500001000">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, @@ -313,7 +313,7 @@ pdn_connectivity_request_test_() -> ]. pdn_connectivity_reject_test_() -> - Bin = hexstream_to_binary(<<"27b31470a6030234d11a3701b6">>), + Bin = binary:decode_hex(<<"27b31470a6030234d11a3701b6">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => integrity_protected_ciphered}, @@ -333,7 +333,7 @@ pdn_connectivity_reject_test_() -> ]. service_request_test_() -> - Bin = hexstream_to_binary(<<"c7c4c952">>), + Bin = binary:decode_hex(<<"c7c4c952">>), Map1 = #{protocol => nas_eps, protocol_discriminator => eps_mobility_management_messages, security_header_type => service_request}, @@ -346,8 +346,29 @@ service_request_test_() -> ]. invalid_message_test() -> - Bin = hexstream_to_binary(<<"deadbeef">>), + Bin = binary:decode_hex(<<"deadbeef">>), ?assertError({case_clause, extension_of_PD}, otc_nas_eps:decode(Bin)). -hexstream_to_binary(In) -> - list_to_binary([binary_to_integer(<>, 16) || <> <= In]). +nas_eps_emm_test_() -> + Bin = binary:decode_hex(<<"17F1E1AF1B1E07453B0BF634F211800188E008A408">>), + Map1 = #{protocol => nas_eps, + security_header_type => integrity_protected, + protocol_discriminator => + eps_mobility_management_messages}, + Map2 = #{protocol => nas_eps_emm, + sequence_number => <<30>>, + message_authentication_code => <<"ñá¯\e">>}, + Map3 = #{protocol => nas_eps, + security_header_type => plain_nas_message, + protocol_discriminator => + eps_mobility_management_messages}, + Map4 = #{protocol => nas_eps_emm, + direction => ue_originated, + message_type => detach_request, + nas_key_set_identifier => 3, + eps_mobile_identity => + <<246,52,242,17,128,1,136,224,8,164,8>>, + detach_type => 11}, + [?_assertEqual({ok, [Map1, Map2, Map3, Map4]}, otc:decode(nas_eps, Bin)), + ?_assertEqual({ok, Bin}, otc:encode([Map1, Map2, Map3, Map4]))]. +