473 lines
22 KiB
Erlang
473 lines
22 KiB
Erlang
% UE FSM
|
|
% (C) 2023 by sysmocom
|
|
%
|
|
% All Rights Reserved
|
|
%
|
|
% This program is free software; you can redistribute it and/or modify
|
|
% it under the terms of the GNU Affero General Public License as
|
|
% published by the Free Software Foundation; either version 3 of the
|
|
% License, or (at your option) any later version.
|
|
%
|
|
% This program is distributed in the hope that it will be useful,
|
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
% GNU General Public License for more details.
|
|
%
|
|
% You should have received a copy of the GNU Affero General Public License
|
|
% along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
%
|
|
% Additional Permission under GNU AGPL version 3 section 7:
|
|
%
|
|
% If you modify this Program, or any covered work, by linking or
|
|
% combining it with runtime libraries of Erlang/OTP as released by
|
|
% Ericsson on http://www.erlang.org (or a modified version of these
|
|
% libraries), containing parts covered by the terms of the Erlang Public
|
|
% License (http://www.erlang.org/EPLICENSE), the licensors of this
|
|
% Program grant you additional permission to convey the resulting work
|
|
% without the need to license the runtime libraries of Erlang/OTP under
|
|
% the GNU Affero General Public License. Corresponding Source for a
|
|
% non-source form of such a combination shall include the source code
|
|
% for the parts of the runtime libraries of Erlang/OTP used as well as
|
|
% that of the covered work.
|
|
|
|
-module(epdg_ue_fsm).
|
|
-behaviour(gen_statem).
|
|
-define(NAME, epdg_ue_fsm).
|
|
|
|
-include_lib("osmo_gsup/include/gsup_protocol.hrl").
|
|
-include_lib("gtplib/include/gtp_packet.hrl").
|
|
-include_lib("gtp_utils.hrl").
|
|
-include("conv.hrl").
|
|
|
|
-export([start/1, stop/1]).
|
|
-export([init/1,callback_mode/0,terminate/3]).
|
|
-export([get_server_name_by_imsi/1, get_pid_by_imsi/1]).
|
|
-export([auth_request/2, lu_request/1, tunnel_request/2, purge_ms_request/1]).
|
|
-export([received_swm_auth_response/2, received_swm_auth_compl_response/2,
|
|
received_swm_session_termination_answer/2, received_swm_abort_session_request/1]).
|
|
-export([received_gtpc_create_session_response/2, received_gtpc_delete_session_response/2, received_gtpc_delete_bearer_request/1]).
|
|
-export([state_new/3, state_wait_auth_resp/3, state_authenticating/3, state_authenticated/3,
|
|
state_wait_create_session_resp/3, state_wait_delete_session_resp/3,
|
|
state_wait_swm_session_termination_answer/3, state_active/3,
|
|
state_dereg_net_initiated_wait_s2b_delete_session_resp/3]).
|
|
|
|
-define(TIMEOUT_VAL_WAIT_GTP_ANSWER, 10000).
|
|
|
|
-record(ue_fsm_data, {
|
|
imsi,
|
|
apn = "internet" :: string(),
|
|
pgw_rem_addr_list = [] :: list(),
|
|
tun_pdp_ctx :: epdg_tun_pdp_ctx,
|
|
tear_down_gsup_needed = false :: boolean(), %% need to send GSUP PurgeMSResp after STR+STA?
|
|
tear_down_gsup_cause = 0 :: integer()
|
|
}).
|
|
|
|
get_server_name_by_imsi(Imsi) ->
|
|
ServerName = lists:concat([?NAME, "_", binary_to_list(Imsi)]),
|
|
list_to_atom(ServerName).
|
|
|
|
get_pid_by_imsi(Imsi) ->
|
|
ServerName = get_server_name_by_imsi(Imsi),
|
|
whereis(ServerName).
|
|
|
|
start(Imsi) ->
|
|
ServerName = get_server_name_by_imsi(Imsi),
|
|
lager:info("ue_fsm start(~p)~n", [ServerName]),
|
|
gen_statem:start({local, ServerName}, ?MODULE, Imsi, [{debug, [trace]}]).
|
|
|
|
stop(SrvRef) ->
|
|
try
|
|
gen_statem:stop(SrvRef)
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
auth_request(Pid, {PdpTypeNr, Apn, EAP}) ->
|
|
lager:info("ue_fsm auth_request~n", []),
|
|
try
|
|
gen_statem:call(Pid, {auth_request, PdpTypeNr, Apn, EAP})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
lu_request(Pid) ->
|
|
lager:info("ue_fsm lu_request~n", []),
|
|
try
|
|
gen_statem:call(Pid, lu_request)
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
tunnel_request(Pid, PCO) ->
|
|
lager:info("ue_fsm tunnel_request(~p)~n", [PCO]),
|
|
try
|
|
gen_statem:call(Pid, {tunnel_request, PCO})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
purge_ms_request(Pid) ->
|
|
lager:info("ue_fsm purge_ms_request~n", []),
|
|
try
|
|
gen_statem:call(Pid, purge_ms_request)
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_swm_auth_response(Pid, Result) ->
|
|
lager:info("ue_fsm received_swm_auth_response ~p~n", [Result]),
|
|
try
|
|
gen_statem:call(Pid, {received_swm_auth_response, Result})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_swm_auth_compl_response(Pid, Result) ->
|
|
lager:info("ue_fsm received_swm_auth_compl_response ~p~n", [Result]),
|
|
try
|
|
gen_statem:call(Pid, {received_swm_auth_compl_response, Result})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_swm_session_termination_answer(Pid, Result) ->
|
|
lager:info("ue_fsm received_swm_session_termination_answer ~p~n", [Result]),
|
|
try
|
|
gen_statem:call(Pid, {received_swm_sta, Result})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_swm_abort_session_request(Pid) ->
|
|
lager:info("ue_fsm received_swm_abort_session_request~n", []),
|
|
try
|
|
gen_statem:call(Pid, received_swm_asr)
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_gtpc_create_session_response(Pid, Result) ->
|
|
lager:info("ue_fsm received_gtpc_create_session_response ~p~n", [Result]),
|
|
try
|
|
gen_statem:call(Pid, {received_gtpc_create_session_response, Result})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_gtpc_delete_session_response(Pid, Msg) ->
|
|
lager:info("ue_fsm received_gtpc_delete_session_response ~p~n", [Msg]),
|
|
try
|
|
gen_statem:call(Pid, {received_gtpc_delete_session_response, Msg})
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
received_gtpc_delete_bearer_request(Pid) ->
|
|
lager:info("ue_fsm received_gtpc_delete_bearer_request~n", []),
|
|
try
|
|
gen_statem:call(Pid, received_gtpc_delete_bearer_request)
|
|
catch
|
|
exit:Err ->
|
|
{error, Err}
|
|
end.
|
|
|
|
|
|
%% ------------------------------------------------------------------
|
|
%% Internal helpers
|
|
%% ------------------------------------------------------------------
|
|
|
|
ev_handle({call, From}, {auth_request, PdpTypeNr, Apn, EAP}, Data) ->
|
|
case epdg_diameter_swm:auth_request(Data#ue_fsm_data.imsi, PdpTypeNr, Apn, EAP) of
|
|
ok -> {next_state, state_wait_auth_resp, Data, [{reply,From,ok}]};
|
|
{error, Err} -> {stop_and_reply, Err, [{reply,From,{error,Err}}], Data}
|
|
end.
|
|
|
|
%% ------------------------------------------------------------------
|
|
%% gen_statem Function Definitions
|
|
%% ------------------------------------------------------------------
|
|
|
|
init(Imsi) ->
|
|
lager:info("ue_fsm init(~p)~n", [Imsi]),
|
|
Data = #ue_fsm_data{imsi = Imsi},
|
|
{ok, state_new, Data}.
|
|
|
|
callback_mode() ->
|
|
[state_functions, state_enter].
|
|
|
|
terminate(Reason, State, Data) ->
|
|
lager:info("terminating ~p with reason ~p state=~p, ~p~n", [?MODULE, Reason, State, Data]),
|
|
case Data#ue_fsm_data.tun_pdp_ctx of
|
|
undefined -> ok;
|
|
_ -> gtp_u_tun:delete_pdp_context(Data#ue_fsm_data.tun_pdp_ctx)
|
|
end,
|
|
ok.
|
|
|
|
state_new(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_new({call, _From} = EvType, {auth_request, PdpTypeNr, Apn, EAP} = EvContent, Data) ->
|
|
lager:info("ue_fsm state_new event=auth_request {~p, ~p, ~p}, ~p~n", [PdpTypeNr, Apn, EAP, Data]),
|
|
ev_handle(EvType, EvContent, Data);
|
|
|
|
state_new({call, From}, purge_ms_request, Data) ->
|
|
lager:info("ue_fsm state_new event=purge_ms_request, ~p~n", [Data]),
|
|
{stop_and_reply, purge_ms_request, [{reply,From,ok}], Data}.
|
|
|
|
state_wait_auth_resp(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_wait_auth_resp({call, From}, {received_swm_auth_response, Result}, Data) ->
|
|
lager:info("ue_fsm state_wait_auth_resp event=received_swm_auth_response Result=~p, ~p~n", [Result, Data]),
|
|
case Result of
|
|
{ok, _AuthTuples} ->
|
|
gsup_server:auth_response(Data#ue_fsm_data.imsi, Result),
|
|
{next_state, state_authenticating, Data, [{reply,From,ok}]};
|
|
{error, DiaRC} ->
|
|
GsupCause = conv:dia_rc_to_gsup_cause(DiaRC),
|
|
gsup_server:auth_response(Data#ue_fsm_data.imsi, {error, GsupCause}),
|
|
{next_state, state_new, Data, [{reply,From,ok}]};
|
|
_ ->
|
|
{next_state, state_new, Data, [{reply,From,{error,unknown}}]}
|
|
end.
|
|
|
|
state_authenticating(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_authenticating({call, _From} = EvType, {auth_request, PdpTypeNr, Apn, EAP} = EvContent, Data) ->
|
|
lager:info("ue_fsm state_authenticating event=auth_request {~p, ~p, ~p}, ~p~n", [PdpTypeNr, Apn, EAP, Data]),
|
|
ev_handle(EvType, EvContent, Data);
|
|
|
|
state_authenticating({call, From}, lu_request, Data) ->
|
|
lager:info("ue_fsm state_authenticating event=lu_request, ~p~n", [Data]),
|
|
% Rx "GSUP CEAI LU Req" is our way of saying Rx "Swm Diameter-EAP REQ (DER) with EAP AVP containing successuful auth":
|
|
case epdg_diameter_swm:auth_compl_request(Data#ue_fsm_data.imsi, Data#ue_fsm_data.apn) of
|
|
ok -> {keep_state, Data, [{reply,From,ok}]};
|
|
{error, Err} -> {stop_and_reply, Err, [{reply,From,{error,Err}}], Data}
|
|
end;
|
|
|
|
% Rx Swm Diameter-EAP Answer (DEA) containing APN-Configuration, triggered by
|
|
% earlier Tx DER EAP AVP containing successuful auth", when we received GSUP LU Req:
|
|
state_authenticating({call, From}, {received_swm_auth_compl_response, Result}, Data) ->
|
|
lager:info("ue_fsm state_authenticating event=lu_request, ~p, ~p~n", [Result, Data]),
|
|
% Rx "GSUP CEAI LU Req" is our way of saying Rx "Swm Diameter-EAP REQ (DER) with EAP AVP containing successuful auth":
|
|
case Result of
|
|
{ok, ResInfo} ->
|
|
% Store PGW Remote address if AAA/HSS signalled them to us:
|
|
case maps:find(pdp_info_list, ResInfo) of
|
|
error ->
|
|
Data1 = Data;
|
|
PGWAddrCandidateList ->
|
|
Data1 = Data#ue_fsm_data{pgw_rem_addr_list = PGWAddrCandidateList}
|
|
end,
|
|
gsup_server:lu_response(Data1#ue_fsm_data.imsi, ok),
|
|
{next_state, state_authenticated, Data1, [{reply,From,ok}]};
|
|
{error, DiaRC} ->
|
|
GsupCause = conv:dia_rc_to_gsup_cause(DiaRC),
|
|
gsup_server:lu_response(Data#ue_fsm_data.imsi, {error, GsupCause}),
|
|
{next_state, state_new, Data, [{reply,From,ok}]}
|
|
end.
|
|
|
|
state_authenticated(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_authenticated({call, _From}, {auth_request, PdpTypeNr, Apn, EAP}, Data) ->
|
|
lager:info("ue_fsm state_authenticated event=auth_request {~p, ~p, ~p}, ~p~n", [PdpTypeNr, Apn, EAP, Data]),
|
|
{next_state, state_new, Data, [postpone]};
|
|
|
|
state_authenticated({call, From}, {tunnel_request, PCO}, Data) ->
|
|
lager:info("ue_fsm state_authenticated event=tunnel_request, ~p~n", [Data]),
|
|
epdg_gtpc_s2b:create_session_req(Data#ue_fsm_data.imsi,
|
|
Data#ue_fsm_data.apn,
|
|
PCO,
|
|
Data#ue_fsm_data.pgw_rem_addr_list),
|
|
{next_state, state_wait_create_session_resp, Data, [{reply,From,ok}]};
|
|
|
|
state_authenticated({call, From}, purge_ms_request, Data) ->
|
|
lager:info("ue_fsm state_authenticated event=purge_ms_request, ~p~n", [Data]),
|
|
Data1 = Data#ue_fsm_data{tear_down_gsup_needed = true},
|
|
{next_state, state_wait_swm_session_termination_answer, Data1, [{reply,From,ok}]};
|
|
|
|
state_authenticated({call, From}, received_gtpc_delete_bearer_request, Data) ->
|
|
lager:info("ue_fsm state_authenticated event=received_gtpc_delete_bearer_request, ~p~n", [Data]),
|
|
gsup_server:cancel_location_request(Data#ue_fsm_data.imsi),
|
|
Data1 = Data#ue_fsm_data{tear_down_gsup_needed = false},
|
|
{next_state, state_wait_swm_session_termination_answer, Data1, [{reply,From,ok}]};
|
|
|
|
state_authenticated({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_authenticated: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,ok}]};
|
|
|
|
state_authenticated(cast, Event, Data) ->
|
|
lager:error("ue_fsm state_authenticated: Unexpected cast event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data}.
|
|
|
|
state_wait_create_session_resp(enter, _OldState, Data) ->
|
|
{keep_state, Data, [{state_timeout,?TIMEOUT_VAL_WAIT_GTP_ANSWER,create_session_timeout}]};
|
|
|
|
state_wait_create_session_resp({call, From}, {received_gtpc_create_session_response, Result}, Data) ->
|
|
lager:info("ue_fsm state_authenticated event=received_gtpc_create_session_response, ~p~n", [Data]),
|
|
case Result of
|
|
{ok, ResInfo} ->
|
|
#{eua := EUA,
|
|
local_teid := LocalTEID,
|
|
remote_teid := RemoteTEID,
|
|
remote_ipv4 := RemoteIPv4 % TODO: remote_ipv6
|
|
} = ResInfo,
|
|
TunPdpCtx = #epdg_tun_pdp_ctx{local_teid = LocalTEID, remote_teid = RemoteTEID,
|
|
eua = EUA, peer_addr = RemoteIPv4},
|
|
Ret = gtp_u_tun:create_pdp_context(TunPdpCtx),
|
|
lager:debug("gtp_u_tun:create_pdp_context(~p) returned ~p~n", [ResInfo, Ret]),
|
|
Data1 = Data#ue_fsm_data{tun_pdp_ctx = TunPdpCtx},
|
|
gsup_server:tunnel_response(Data1#ue_fsm_data.imsi, Result),
|
|
{next_state, state_active, Data1, [{reply,From,ok}]};
|
|
{error, GtpCause} ->
|
|
GsupCause = conv:cause_gtp2gsup(GtpCause),
|
|
gsup_server:tunnel_response(Data#ue_fsm_data.imsi, {error, GsupCause}),
|
|
{next_state, state_authenticated, Data, [{reply,From,ok}]}
|
|
end;
|
|
|
|
state_wait_create_session_resp({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_wait_delete_session_resp: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,{error,unexpected_event}}]};
|
|
|
|
state_wait_create_session_resp(state_timeout, create_session_timeout, Data) ->
|
|
lager:error("ue_fsm state_wait_create_session_resp: Timeout ~p, ~p~n", [create_session_timeout, Data]),
|
|
gsup_server:tunnel_response(Data#ue_fsm_data.imsi, {error, ?GSUP_CAUSE_CONGESTION}),
|
|
{next_state, state_authenticated, Data}.
|
|
|
|
state_active(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_active({call, _From}, {auth_request, PdpTypeNr, Apn, EAP}, Data) ->
|
|
lager:info("ue_fsm state_active event=auth_request {~p, ~p, ~p}, ~p~n", [PdpTypeNr, Apn, EAP, Data]),
|
|
gtp_u_tun:delete_pdp_context(Data#ue_fsm_data.tun_pdp_ctx),
|
|
Data1 = Data#ue_fsm_data{tun_pdp_ctx = undefined},
|
|
{next_state, state_new, Data1, [postpone]};
|
|
|
|
state_active({call, From}, purge_ms_request, Data) ->
|
|
lager:info("ue_fsm state_active event=purge_ms_request, ~p~n", [Data]),
|
|
gtp_u_tun:delete_pdp_context(Data#ue_fsm_data.tun_pdp_ctx),
|
|
Data1 = Data#ue_fsm_data{tun_pdp_ctx = undefined},
|
|
case epdg_gtpc_s2b:delete_session_req(Data1#ue_fsm_data.imsi) of
|
|
ok -> {next_state, state_wait_delete_session_resp, Data1, [{reply,From,ok}]};
|
|
{error, Err} -> {keep_state, Data1, [{reply,From,{error, Err}}]}
|
|
end;
|
|
|
|
state_active({call, From}, received_gtpc_delete_bearer_request, Data) ->
|
|
lager:info("ue_fsm state_active event=received_gtpc_delete_bearer_request, ~p~n", [Data]),
|
|
gtp_u_tun:delete_pdp_context(Data#ue_fsm_data.tun_pdp_ctx),
|
|
gsup_server:cancel_location_request(Data#ue_fsm_data.imsi),
|
|
Data1 = Data#ue_fsm_data{tun_pdp_ctx = undefined, tear_down_gsup_needed = false},
|
|
{next_state, state_wait_swm_session_termination_answer, Data1, [{reply,From,ok}]};
|
|
|
|
%%% network (HSS/AAA) initiated de-registation requested:
|
|
state_active({call, From}, received_swm_asr, Data) ->
|
|
lager:info("ue_fsm state_active event=received_swm_asr, ~p~n", [Data]),
|
|
gsup_server:cancel_location_request(Data#ue_fsm_data.imsi),
|
|
gtp_u_tun:delete_pdp_context(Data#ue_fsm_data.tun_pdp_ctx),
|
|
Data1 = Data#ue_fsm_data{tun_pdp_ctx = undefined, tear_down_gsup_needed = false},
|
|
{next_state, state_dereg_net_initiated_wait_s2b_delete_session_resp, Data1, [{reply,From,ok}]};
|
|
|
|
state_active({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_active: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,ok}]};
|
|
|
|
state_active(cast, Event, Data) ->
|
|
lager:error("ue_fsm state_active: Unexpected cast event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data}.
|
|
|
|
state_wait_delete_session_resp(enter, _OldState, Data) ->
|
|
{keep_state, Data};
|
|
|
|
state_wait_delete_session_resp({call, From}, {received_gtpc_delete_session_response, _Resp = #gtp{version = v2, type = delete_session_response, ie = IEs}}, Data) ->
|
|
lager:info("ue_fsm state_wait_delete_session_resp event=received_gtpc_delete_session_response, ~p~n", [Data]),
|
|
#{{v2_cause,0} := CauseIE} = IEs,
|
|
GtpCause = gtp_utils:enum_v2_cause(CauseIE#v2_cause.v2_cause),
|
|
GsupCause = conv:cause_gtp2gsup(GtpCause),
|
|
lager:debug("Cause: GTP_atom=~p -> GTP_int=~p -> GSUP_int=~p~n", [CauseIE#v2_cause.v2_cause, GtpCause, GsupCause]),
|
|
Data1 = Data#ue_fsm_data{tear_down_gsup_needed = true},
|
|
case GsupCause of
|
|
0 -> Data2 = Data1;
|
|
_ -> Data2 = Data1#ue_fsm_data{tear_down_gsup_cause = GsupCause}
|
|
end,
|
|
{next_state, state_wait_swm_session_termination_answer, Data2, [{reply,From,ok}]};
|
|
|
|
state_wait_delete_session_resp({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_wait_delete_session_resp: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,{error,unexpected_event}}]}.
|
|
|
|
state_wait_swm_session_termination_answer(enter, _OldState, Data) ->
|
|
% Send STR towards AAA-Server
|
|
% % 3GPP TS 29.273 7.1.2.3
|
|
lager:info("ue_fsm state_wait_swm_session_termination_answer event=enter, ~p~n", [Data]),
|
|
case epdg_diameter_swm:session_termination_request(Data#ue_fsm_data.imsi) of
|
|
ok -> {keep_state, Data};
|
|
{error, _Err} ->
|
|
case Data#ue_fsm_data.tear_down_gsup_needed of
|
|
true -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, {error, ?GSUP_CAUSE_NET_FAIL});
|
|
false -> ok
|
|
end,
|
|
{keep_state, Data}
|
|
end;
|
|
|
|
state_wait_swm_session_termination_answer({call, From}, {received_swm_sta, DiaRC}, Data) ->
|
|
lager:info("ue_fsm state_wait_swm_session_termination_answer event=received_swm_sta, ~p~n", [Data]),
|
|
case Data#ue_fsm_data.tear_down_gsup_needed of
|
|
true ->
|
|
case {DiaRC#epdg_dia_rc.result_code, Data#ue_fsm_data.tear_down_gsup_cause} of
|
|
{2001, 0} -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, ok);
|
|
{2001, _} -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, {error, Data#ue_fsm_data.tear_down_gsup_cause});
|
|
_ -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, {error, ?GSUP_CAUSE_NET_FAIL})
|
|
end;
|
|
false -> ok
|
|
end,
|
|
{stop_and_reply, normal, [{reply,From,ok}], Data};
|
|
|
|
state_wait_swm_session_termination_answer({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_wait_delete_session_resp: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,{error,unexpected_event}}]}.
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%% state_dereg_net_initiated_wait_s2b_delete_session_resp:
|
|
%% Network (AAA/HSS) initiated de-registration: We have informed UE (GSUP), and
|
|
%% have triggered GTPCv1 Delete Session Req against PGW.
|
|
%% Wait for GTPCv1 Delete Session Response, ssend SWm ASA to AAAA and terminate FSM.
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
state_dereg_net_initiated_wait_s2b_delete_session_resp(enter, _OldState, Data) ->
|
|
case epdg_gtpc_s2b:delete_session_req(Data#ue_fsm_data.imsi) of
|
|
ok ->
|
|
{keep_state, Data, {state_timeout,?TIMEOUT_VAL_WAIT_GTP_ANSWER,s2b_delete_session_timeout}};
|
|
{error, Err} ->
|
|
epdg_diameter_swm:abort_session_answer(Data#ue_fsm_data.imsi),
|
|
{stop, {error,Err}}
|
|
end;
|
|
|
|
state_dereg_net_initiated_wait_s2b_delete_session_resp({call, From}, {received_gtpc_delete_session_response, _Resp = #gtp{version = v2, type = delete_session_response, ie = IEs}}, Data) ->
|
|
lager:info("ue_fsm state_wait_delete_session_resp event=state_dereg_net_initiated_wait_s2b_delete_session_resp, ~p~n", [Data]),
|
|
#{{v2_cause,0} := CauseIE} = IEs,
|
|
GtpCause = gtp_utils:enum_v2_cause(CauseIE#v2_cause.v2_cause),
|
|
lager:debug("Cause: GTP_atom=~p -> GTP_int=~p~n", [CauseIE#v2_cause.v2_cause, GtpCause]),
|
|
epdg_diameter_swm:abort_session_answer(Data#ue_fsm_data.imsi),
|
|
{stop_and_reply, normal, [{reply,From,ok}], Data};
|
|
|
|
state_dereg_net_initiated_wait_s2b_delete_session_resp({call, From}, Event, Data) ->
|
|
lager:error("ue_fsm state_dereg_net_initiated_wait_s2b_delete_session_resp: Unexpected call event ~p, ~p~n", [Event, Data]),
|
|
{keep_state, Data, [{reply,From,ok}]};
|
|
|
|
|
|
state_dereg_net_initiated_wait_s2b_delete_session_resp(state_timeout, s2b_delete_session_timeout, Data) ->
|
|
lager:error("ue_fsm state_dereg_net_initiated_wait_s2b_delete_session_resp: Timeout ~p, ~p~n", [s2b_delete_session_timeout, Data]),
|
|
epdg_diameter_swm:abort_session_answer(Data#ue_fsm_data.imsi),
|
|
{stop, normal}.
|