fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41762?usp=email )
Change subject: s1ap_utils: add API for building S1 SETUP FAILURE PDU ......................................................................
s1ap_utils: add API for building S1 SETUP FAILURE PDU
This API will be used in a follow-up patch adding the MME pooling. Take a chance to add a parsing test for the new PDU blob.
Change-Id: I5a4e060e0a2ebdfbcfafac42f9de2e49ac3583b8 Related: SYS#7052 --- M src/s1ap_utils.erl M test/s1ap_samples.erl M test/s1ap_utils_test.erl 3 files changed, 89 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/62/41762/1
diff --git a/src/s1ap_utils.erl b/src/s1ap_utils.erl index 6f7e6b6..2ecd0bf 100644 --- a/src/s1ap_utils.erl +++ b/src/s1ap_utils.erl @@ -40,6 +40,8 @@ parse_plmn_id/1, parse_enb_id/1, genb_id_str/1]). +-export([build_pdu/1, + build_s1setup_fail_pdu/1]).
-include_lib("kernel/include/logger.hrl").
@@ -120,6 +122,34 @@ MCC ++ "-" ++ MNC ++ "-" ++ integer_to_list(ENBId).
+%% Build an S1AP PDU +-spec build_pdu(s1ap_pdu_info()) -> {ok, binary()} | {error, term()}. +build_pdu({MsgType, Content}) -> + case build_pdu(MsgType, Content) of + {error, Error} -> + ?LOG_ERROR("Failed to build an S1AP PDU: ~p", [Error]), + {error, {build_pdu, Error}}; + PDU -> + try encode_pdu(PDU) of + {ok, Data} -> + {ok, Data}; + {error, Error} -> + ?LOG_ERROR("S1AP PDU encoding failed: ~p", [Error]), + {error, {encode_pdu, Error}} + catch + Exception:Reason:StackTrace -> + ?LOG_ERROR("An exception occurred: ~p, ~p, ~p", [Exception, Reason, StackTrace]), + {error, encode_pdu} + end + end. + + +%% Build an S1AP S1 SETUP FAILURE PDU +-spec build_s1setup_fail_pdu(proplists:proplist()) -> {ok, binary()} | {error, term()}. +build_s1setup_fail_pdu(Content) -> + build_pdu({{?'id-S1Setup', unsuccessfulOutcome}, Content}). + + %% ------------------------------------------------------------------ %% private API %% ------------------------------------------------------------------ @@ -207,4 +237,28 @@ lists:map(fun parse_ie/1, IEs).
+-spec build_pdu(MsgType, Content) -> s1ap_pdu() | {error, term()} + when MsgType :: s1ap_msg_type(), + Content :: proplists:proplist(). +build_pdu({?'id-S1Setup' = PC, + unsuccessfulOutcome = Outcome}, Content) -> + Cause = proplists:get_value(?'id-Cause', Content, {misc, unspecified}), + TimeToWait = proplists:get_value(?'id-TimeToWait', Content, v10s), + IEs = [#'ProtocolIE-Field'{id = ?'id-Cause', + criticality = ignore, + value = Cause}, + #'ProtocolIE-Field'{id = ?'id-TimeToWait', + criticality = ignore, + value = TimeToWait}], + {Outcome, + #'UnsuccessfulOutcome'{procedureCode = PC, + criticality = reject, + value = #'S1SetupFailure'{protocolIEs = IEs}}}; + + +build_pdu(MsgType, _Content) -> + ?LOG_ERROR("~p(~p): not implemented", [?FUNCTION_NAME, MsgType]), + {error, not_implemented}. + + %% vim:set ts=4 sw=4 et: diff --git a/test/s1ap_samples.erl b/test/s1ap_samples.erl index e3c3ac1..183aad6 100644 --- a/test/s1ap_samples.erl +++ b/test/s1ap_samples.erl @@ -2,6 +2,7 @@
-export([s1_setup_req_pdu/0, s1_setup_rsp_pdu/0, + s1_setup_fail_pdu/0, e_rab_setup_req_pdu/2, e_rab_setup_rsp_pdu/2, e_rab_setup_rsp_fail_pdu/0, @@ -48,6 +49,14 @@ >>.
+%% S1 SETUP FAILURE +s1_setup_fail_pdu() -> + << 16#40, 16#11, 16#00, 16#0d, 16#00, 16#00, 16#02, 16#00, + 16#02, 16#40, 16#01, 16#44, 16#00, 16#41, 16#40, 16#01, + 16#30 + >>. + + %% [eNB <- MME] E-RAB SETUP REQUEST e_rab_setup_req_pdu(TLA, TEID) when is_binary(TLA), is_integer(TEID) -> diff --git a/test/s1ap_utils_test.erl b/test/s1ap_utils_test.erl index ca63606..9285da8 100644 --- a/test/s1ap_utils_test.erl +++ b/test/s1ap_utils_test.erl @@ -16,7 +16,7 @@ %% actual testcases %% ------------------------------------------------------------------
-s1ap_setup_req_test_() -> +s1ap_setup_req_parse_test_() -> {MsgType, IEs} = s1ap_utils:parse_pdu(s1ap_samples:s1_setup_req_pdu()), [?_assertEqual({?'id-S1Setup', initiatingMessage}, MsgType), ?_assertEqualIE(?'id-Global-ENB-ID', #{enb_id => 0, @@ -25,7 +25,7 @@ ?_assertMatchIE(?'id-SupportedTAs', [12345])]. %% we only parse the TACs
-s1ap_setup_rsp_test_() -> +s1ap_setup_rsp_parse_test_() -> {MsgType, IEs} = s1ap_utils:parse_pdu(s1ap_samples:s1_setup_rsp_pdu()), [?_assertEqual({?'id-S1Setup', successfulOutcome}, MsgType), ?_assertEqualIE(?'id-MMEname', "open5gs-mme0"), @@ -33,4 +33,28 @@ ?_assertEqualIE(?'id-RelativeMMECapacity', 16#ff)].
+s1ap_setup_fail_parse_test_() -> + {MsgType, IEs} = s1ap_utils:parse_pdu(s1ap_samples:s1_setup_fail_pdu()), + [?_assertEqual({?'id-S1Setup', unsuccessfulOutcome}, MsgType), + ?_assertEqualIE(?'id-Cause', {misc, unspecified}), + ?_assertEqualIE(?'id-TimeToWait', v10s)]. + + +s1ap_setup_fail_build_test_() -> + [?_assertEqual({ok, s1ap_samples:s1_setup_fail_pdu()}, + s1ap_utils:build_s1setup_fail_pdu([]))]. + + +build_pdu_error_test_() -> + TraceStartReq = {{?'id-TraceStart', initiatingMessage}, []}, + S1SetupFailure = {{?'id-S1Setup', unsuccessfulOutcome}, + [{?'id-TimeToWait', 42}]}, %% wrong value + [%% test building a non-implemented PDU + ?_assertEqual({error, {build_pdu, not_implemented}}, + s1ap_utils:build_pdu(TraceStartReq)), + %% test building a PDU with a wrong user-supplied IE + ?_assertMatch({error, {encode_pdu, {asn1, _}}}, + s1ap_utils:build_pdu(S1SetupFailure))]. + + %% vim:set ts=4 sw=4 et: