pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/36262?usp=email )
Change subject: WIP: Implement RTR Deregistration-Reason PERMANENT_TERMINATION ......................................................................
WIP: Implement RTR Deregistration-Reason PERMANENT_TERMINATION
Change-Id: I57f2e02dc4034b63c118e4a4139b2830e38a2138 --- M config/sys.config M src/aaa_diameter_s6b.erl M src/aaa_diameter_s6b_cb.erl M src/aaa_diameter_swm.erl M src/aaa_diameter_swx_cb.erl M src/aaa_ue_fsm.erl M src/conv.erl M src/epdg_diameter_swm.erl M src/epdg_ue_fsm.erl 9 files changed, 294 insertions(+), 35 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-epdg refs/changes/62/36262/1
diff --git a/config/sys.config b/config/sys.config index a40fd23..2677c3d 100755 --- a/config/sys.config +++ b/config/sys.config @@ -28,6 +28,7 @@ {dia_s6b_watchdog_config, [{okay, 3}, {suspect, 1}]}, + {dia_s6b_transmit_timer, 10000}, {dia_s6b_vendor_id, 0}, {dia_s6b_origin_host, "aaa.localdomain"}, {dia_s6b_origin_realm, "localdomain"}, diff --git a/src/aaa_diameter_s6b.erl b/src/aaa_diameter_s6b.erl index baf251f..c9afc37 100644 --- a/src/aaa_diameter_s6b.erl +++ b/src/aaa_diameter_s6b.erl @@ -49,6 +49,7 @@ %% gen_server Function Exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, peer_down/3]). -export([code_change/3]). +-export([tx_as_request/1]). -export([tx_aa_answer/2, tx_st_answer/2]).
%% Diameter Application Definitions @@ -68,6 +69,7 @@ -define(ENV_DEFAULT_DIAMETER_CONNECT_TIMER_MS, 30000). -define(ENV_DEFAULT_DIAMETER_WATCHDOG_TIMER_MS, 30000). -define(ENV_DEFAULT_DIAMETER_WATCHDOG_CFG, [{okay, 3}, {suspect, 1}]). +-define(ENV_DEFAULT_DIAMETER_TRANSMIT_TIMER_MS, 10000).
-define(VENDOR_ID_3GPP, 10415). -define(VENDOR_ID_3GPP2, 5535). @@ -93,6 +95,10 @@ {module, ?CALLBACK_MOD}, {answer_errors, callback}]}]).
+-record(s6b_state, { + tx_timeout :: non_neg_integer() +}). + %% @doc starts gen_server implementation process -spec start() -> ok | {error, term()}. start() -> @@ -111,17 +117,18 @@ gen_server:cast(?SERVER, {peer_down, SvcName, Peer}), ok.
-init(State) -> +init([]) -> Proto = application:get_env(?ENV_APP_NAME, dia_s6b_proto, ?ENV_DEFAULT_DIAMETER_PROTO), Ip = application:get_env(?ENV_APP_NAME, dia_s6b_local_ip, ?ENV_DEFAULT_DIAMETER_REMOTE_IP), Port = application:get_env(?ENV_APP_NAME, dia_s6b_local_port, ?ENV_DEFAULT_DIAMETER_REMOTE_PORT), ConnectTimer = application:get_env(?ENV_APP_NAME, dia_s6b_connect_timer, ?ENV_DEFAULT_DIAMETER_CONNECT_TIMER_MS), WatchdogTimer = application:get_env(?ENV_APP_NAME, dia_s6b_watchdog_timer, ?ENV_DEFAULT_DIAMETER_WATCHDOG_TIMER_MS), WatchdogConfig = application:get_env(?ENV_APP_NAME, diameter_watchdog_config, ?ENV_DEFAULT_DIAMETER_WATCHDOG_CFG), + TxTimer = application:get_env(?ENV_APP_NAME, dia_s6b_transmit_timer, ?ENV_DEFAULT_DIAMETER_TRANSMIT_TIMER_MS), ok = diameter:start_service(?MODULE, ?SERVICE), % lager:info("DiaServices is ~p~n", [DiaServ]), {ok, _} = listen({address, Proto, Ip, Port}, {timer, ConnectTimer, WatchdogTimer, WatchdogConfig}), - {ok, State}. + {ok, #s6b_state{tx_timeout = TxTimer}}.
tx_aa_answer(Pid, DiaRC) -> % handle_request(AAR) was spawned into its own process, and it's blocked waiting for AAA: @@ -131,6 +138,27 @@ % handle_request(STR) was spawned into its own process, and it's blocked waiting for STA: Pid ! {sta, DiaRC}.
+tx_as_request(Imsi) -> + gen_server:call(?SERVER, {asr, Imsi}). + +handle_call({asr, Imsi}, _From, State) -> + lager:debug("S6b Tx ASR Imsi=~p~n", [Imsi]), + SessionId = diameter:session_id(application:get_env(?ENV_APP_NAME, dia_s6b_origin_host, ?ENV_DEFAULT_ORIG_HOST)), + ASR = #'ASR'{'Session-Id' = SessionId, + 'Auth-Application-Id' = ?DIAMETER_APP_ID_S6b, + 'User-Name' = Imsi, + 'Auth-Session-State' = ?'AUTH-SESSION-STATE_NO_STATE_MAINTAINED' + }, + lager:debug("S6b Tx ASR: ~p~n", [ASR]), + Ret = diameter_call(ASR, State), + case Ret of + ok -> + {reply, ok, State}; + {error, Err} -> + lager:error("Error: ~w~n", [Err]), + {reply, {error, Err}, State} + end; + handle_call(Info, _From, State) -> error_logger:error_report(["unknown handle_call", {module, ?MODULE}, {info, Info}, {state, State}]).
@@ -189,4 +217,7 @@ tmod(sctp) -> diameter_sctp.
+diameter_call(Msg, State) -> + diameter:call(?SVC_NAME, ?APP_ALIAS, Msg, [{timeout, State#s6b_state.tx_timeout}, + detach]).
diff --git a/src/aaa_diameter_s6b_cb.erl b/src/aaa_diameter_s6b_cb.erl index a56a7ca..ad50e74 100644 --- a/src/aaa_diameter_s6b_cb.erl +++ b/src/aaa_diameter_s6b_cb.erl @@ -29,23 +29,31 @@ {ok, Peer}.
%% prepare_request/3 -prepare_request(_Req, _SvcName, _Peer) -> - lager:error("Unexpected prepare_request(): ~p~n", [_Req]), - ?UNEXPECTED. +prepare_request(#diameter_packet{msg = [ T | Avps ]}, _, {_, Caps}) + when is_list(Avps) -> + #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, + {send, + [T, + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Host', [DH]}, + {'Destination-Realm', DR} + | Avps]}; +% TODO: is there a simple way to capture all the following requests? +prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}) + when is_record(Req, 'ASR') -> + #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, + Msg = Req#'ASR'{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Destination-Realm' = DR, + 'Destination-Host' = DH}, + lager:debug("S6b prepare_request: ~p~n", [Msg]), + {send, Msg}.
%% prepare_retransmit/3 prepare_retransmit(Packet, SvcName, Peer) -> prepare_request(Packet, SvcName, Peer).
-%% handle_answer/4 - -%% Since client.erl has detached the call when using the list -%% encoding and not otherwise, output to the terminal in the -%% the former case, return in the latter. - -handle_answer(_Packet, _Request, _SvcName, _Peer) -> - ?UNEXPECTED. - %% handle_error/4 handle_error(Reason, Request, _SvcName, _Peer) when is_list(Request) -> lager:error("Request error: ~p~n", [Reason]), @@ -123,4 +131,21 @@
handle_request(Packet, _SvcName, Peer) -> lager:error("S6b Rx unexpected msg from ~p: ~p~n", [Peer, Packet]), - erlang:error({unexpected, ?MODULE, ?LINE}). \ No newline at end of file + erlang:error({unexpected, ?MODULE, ?LINE}). + +%% handle_answer/4 +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer) when is_record(Msg, 'ASA') -> + lager:info("S6b Rx ASA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), + #'ASA'{'Result-Code' = ResultCode} = Msg, + DiaRC = #epdg_dia_rc{result_code = ResultCode}, + case conv:dia_rc_success(DiaRC) of + ok -> + aaa_ue_fsm:ev_rx_s6b_asa(ok); + _ -> + aaa_ue_fsm:ev_rx_s6b_asa({error, DiaRC}) + end, + {ok, Msg}; + +handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) -> + lager:notice("S6b Rx unexpected ~p: ~p~n", [Peer, Msg]), + {ok, Msg}. \ No newline at end of file diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl index 2e39048..db06e30 100644 --- a/src/aaa_diameter_swm.erl +++ b/src/aaa_diameter_swm.erl @@ -14,8 +14,8 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2]). -export([code_change/3, terminate/2]).
--export([auth_request/4, auth_compl_request/2, session_termination_request/1]). --export([auth_response/2, auth_compl_response/2, session_termination_answer/2]). +-export([auth_request/4, auth_compl_request/2, session_termination_request/1, abort_session_answer/1]). +-export([auth_response/2, auth_compl_response/2, session_termination_answer/2, tx_as_request/1]).
-define(SERVER, ?MODULE).
@@ -38,6 +38,9 @@ session_termination_answer(Imsi, Result) -> _Result = gen_server:call(?SERVER, {sta, Imsi, Result}).
+tx_as_request(Imsi) -> + _result = gen_server:call(?SERVER, {asr, Imsi}). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Rx from emulated SWm wire: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -50,6 +53,9 @@ session_termination_request(Imsi) -> gen_server:cast(?SERVER, {str, Imsi}).
+abort_session_answer(Imsi) -> + gen_server:cast(?SERVER, {asa, Imsi}). + handle_cast({epdg_auth_req, Imsi, PdpTypeNr, Apn, EAP}, State) -> case aaa_ue_fsm:get_pid_by_imsi(Imsi) of undefined -> {ok, Pid} = aaa_ue_fsm:start(Imsi); @@ -85,6 +91,15 @@ end, {noreply, State};
+handle_cast({asa, Imsi}, State) -> + case aaa_ue_fsm:get_pid_by_imsi(Imsi) of + Pid when is_pid(Pid) -> + aaa_ue_fsm:ev_rx_swm_asa(Pid); + undefined -> + ok + end, + {noreply, State}; + handle_cast(Info, S) -> error_logger:error_report(["unknown handle_cast", {module, ?MODULE}, {info, Info}, {state, S}]), {noreply, S}. @@ -105,6 +120,10 @@ epdg_diameter_swm:session_termination_answer(Imsi, DiaRC), {reply, ok, State};
+handle_call({asr, Imsi}, _From, State) -> + epdg_diameter_swm:abort_session_request(Imsi), + {reply, ok, State}; + handle_call(Request, From, S) -> error_logger:error_report(["unknown handle_call", {module, ?MODULE}, {request, Request}, {from, From}, {state, S}]), {noreply, S}. diff --git a/src/aaa_diameter_swx_cb.erl b/src/aaa_diameter_swx_cb.erl index 4936c24..c6fe51f 100644 --- a/src/aaa_diameter_swx_cb.erl +++ b/src/aaa_diameter_swx_cb.erl @@ -78,10 +78,18 @@ 'Vendor-Specific-Application-Id' = VendorAppId, 'Auth-Session-State' = AuthSessState, 'User-Name' = Imsi, - 'Deregistration-Reason' = _DeregReason} = Req, + 'Deregistration-Reason' = DeregReason} = Req, case aaa_ue_fsm:get_pid_by_imsi(Imsi) of Pid when is_pid(Pid) -> - aaa_ue_fsm:stop(Pid), + case DeregReason of + #'Deregistration-Reason'{'Reason-Code' = ?'REASON-CODE_PERMANENT_TERMINATION'} -> + case aaa_ue_fsm:ev_rx_swx_rtr(Pid) of + {error, _} -> aaa_ue_fsm:stop(Pid); + _ -> ok + end; + _ -> + aaa_ue_fsm:stop(Pid) + end, Res = 2001, %% Success ERes = []; undefined -> @@ -109,7 +117,7 @@ #'MAA'{'Result-Code' = ResultCodeOpt, 'Experimental-Result' = ExperimentalResultOpt} = Msg, DiaRC = parse_epdg_dia_rc(ResultCodeOpt, ExperimentalResultOpt), - case dia_rc_success(DiaRC) of + case conv:dia_rc_success(DiaRC) of ok -> #'MAA'{'SIP-Auth-Data-Item' = SipAuthTuples} = Msg, AuthTuples = lists:map(fun dia_sip2epdg_auth_tuple/1, SipAuthTuples), @@ -127,7 +135,7 @@ #'SAA'{'Result-Code' = ResultCodeOpt, 'Experimental-Result' = ExperimentalResultOpt} = Msg, DiaRC = parse_epdg_dia_rc(ResultCodeOpt, ExperimentalResultOpt), - case dia_rc_success(DiaRC) of + case conv:dia_rc_success(DiaRC) of ok -> #'SAA'{'Non-3GPP-User-Data' = N3UA} = Msg, PGWAddresses = parse_pgw_addr_from_N3UA(N3UA), @@ -165,10 +173,6 @@ %% Internal Function Definitions %% ------------------------------------------------------------------
-dia_rc_success(#epdg_dia_rc{result_code = 2001}) -> ok; -dia_rc_success(#epdg_dia_rc{result_code = 2002}) -> ok; -dia_rc_success(_) -> invalid_result_code. - parse_epdg_dia_rc([], []) -> #epdg_dia_rc{vendor_id = undefined, result_code = 2001 }; parse_epdg_dia_rc([ResultCode], []) -> diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl index 52057ba..0788985 100644 --- a/src/aaa_ue_fsm.erl +++ b/src/aaa_ue_fsm.erl @@ -42,9 +42,19 @@ -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([ev_swm_auth_req/2, ev_swm_auth_compl/2, ev_rx_swm_str/1, ev_rx_swx_maa/2, ev_rx_swx_saa/2, - ev_rx_s6b_aar/2, ev_rx_s6b_str/1]). --export([state_new/3, state_wait_swx_maa/3, state_wait_swx_saa/3, state_authenticated/3, state_authenticated_wait_swx_saa/3]). +-export([ev_swm_auth_req/2, ev_swm_auth_compl/2, ev_rx_swm_str/1, ev_rx_swm_asa/1, + ev_rx_swx_maa/2, ev_rx_swx_saa/2, ev_rx_swx_rtr/1, + ev_rx_s6b_aar/2, ev_rx_s6b_str/1, ev_rx_s6b_asa/2]). +-export([state_new/3, + state_wait_swx_maa/3, + state_wait_swx_saa/3, + state_authenticated/3, + state_authenticated_wait_swx_saa/3, + state_dereg_net_initiated_wait_s6b_asa/3, + state_dereg_net_initiated_wait_swm_asa/3]). + +-define(TIMEOUT_VAL_WAIT_S6b_ANSWER, 10000). +-define(TIMEOUT_VAL_WAIT_SWm_ANSWER, 10000).
-record(ue_fsm_data, { imsi = unknown :: string(), @@ -102,6 +112,15 @@ {error, Err} end.
+ev_rx_swm_asa(Pid) -> + lager:info("ue_fsm ev_rx_swm_asa~n", []), + try + gen_statem:call(Pid, rx_swm_asa) + catch + exit:Err -> + {error, Err} + end. + ev_rx_swx_maa(Pid, Result) -> lager:info("ue_fsm ev_rx_swx_maa~n", []), try @@ -120,6 +139,15 @@ {error, Err} end.
+ev_rx_swx_rtr(Pid) -> + lager:info("ue_fsm ev_rx_swx_rtr~n", []), + try + gen_statem:call(Pid, rx_swx_rtr) + catch + exit:Err -> + {error, Err} + end. + ev_rx_s6b_aar(Pid, {Apn, AgentInfoOpt}) -> lager:info("ue_fsm ev_rx_s6b_aar: ~p ~p~n", [Apn, AgentInfoOpt]), try @@ -129,6 +157,15 @@ {error, Err} end.
+ev_rx_s6b_asa(Pid, Result) -> + lager:info("ue_fsm ev_rx_s6b_asa: ~p~n", [Result]), + try + gen_statem:call(Pid, {rx_s6b_asa, Result}) + catch + exit:Err -> + {error, Err} + end. + ev_rx_s6b_str(Pid) -> lager:info("ue_fsm ev_rx_s6b_str~n", []), try @@ -223,7 +260,7 @@ DiaRC = 5002, %% UNKNOWN_SESSION_ID {keep_state, Data, [{reply,From,{error, DiaRC}}]}; {true, true} -> %% The other session is still active, no need to send SAR Type=USER_DEREGISTRATION - lager:info("ue_fsm state_authenticated event=rx_swn_str: PGW session still active, skip updating the HSS~n", []), + lager:info("ue_fsm state_authenticated event=rx_swm_str: PGW session still active, skip updating the HSS~n", []), Data1 = Data#ue_fsm_data{epdg_sess_active = false}, {keep_state, Data1, [{reply,From,{ok, 2001}}]}; {true, false} -> %% All sessions will now be gone, trigger SAR Type=USER_DEREGISTRATION @@ -264,6 +301,13 @@ lager:info("ue_fsm state_authenticated event=swm_auth_req {~p, ~p, ~p}, ~p~n", [PdpTypeNr, Apn, EAP, Data]), {next_state, state_new, Data, [postpone]};
+state_authenticated({call, From}, rx_swx_rtr, Data) -> + lager:info("ue_fsm state_authenticated event=rx_swx_rtr ~p~n", [Data]), + case {Data#ue_fsm_data.pgw_sess_active, Data#ue_fsm_data.epdg_sess_active} of + {true, _} -> {next_state, state_dereg_net_initiated_wait_s6b_asa, Data, [{reply,From,ok}]}; + {false, _} -> {next_state, state_dereg_net_initiated_wait_s6b_asa, Data, [{reply,From,ok}]} %% TODO: proper state for s6b + end; + state_authenticated({call, From}, Ev, Data) -> lager:info("ue_fsm state_authenticated: Unexpected call event ~p, ~p~n", [Ev, Data]), {keep_state, Data, [{reply,From,ok}]}. @@ -293,4 +337,36 @@ Data1 = Data#ue_fsm_data{pgw_sess_active = false, s6b_resp_pid = undefined}, {next_state, state_new, Data1, [{reply,From,ok}]} end - end. \ No newline at end of file + end. + +%% HSS asked us to do deregistration towards the user. +%% Transmit S6b ASR towards PGW and wait for ASA back. +state_dereg_net_initiated_wait_s6b_asa(enter, _OldState, Data) -> + aaa_diameter_s6b:tx_as_request(Data#ue_fsm_data.imsi), + {keep_state, Data, {state_timeout,?TIMEOUT_VAL_WAIT_S6b_ANSWER,s6b_asa_timeout}}; + +state_dereg_net_initiated_wait_s6b_asa({call, From}, {rx_s6b_asa, _Result}, Data) -> + {next_state, state_dereg_net_initiated_wait_swm_asa, Data, [{reply,From,ok}]}; + +state_dereg_net_initiated_wait_s6b_asa({call, From}, Ev, Data) -> + lager:info("ue_fsm state_dereg_net_initiated_wait_s6b_asa: Unexpected call event ~p, ~p~n", [Ev, Data]), + {keep_state, Data, [{reply,From,ok}]}; + +state_dereg_net_initiated_wait_s6b_asa(state_timeout, s6b_asa_timeout, Data) -> + {next_state, state_dereg_net_initiated_wait_swm_asa, Data}. + +%% HSS asked us to do deregistration towards the user. +%% S6b (PGW) was already torn down. Now transmit SWm ASR towards ePDG and wait for ASA back. +state_dereg_net_initiated_wait_swm_asa(enter, _OldState, Data) -> + aaa_diameter_swm:tx_as_request(Data#ue_fsm_data.imsi), + {keep_state, Data, {state_timeout,?TIMEOUT_VAL_WAIT_SWm_ANSWER,swm_asa_timeout}}; + +state_dereg_net_initiated_wait_swm_asa({call, From}, {rx_swm_asa, _Result}, Data) -> + {stop_and_reply, normal, [{reply,From,ok}], Data}; + +state_dereg_net_initiated_wait_swm_asa({call, From}, Ev, Data) -> + lager:info("ue_fsm state_dereg_net_initiated_wait_swm_asa: Unexpected call event ~p, ~p~n", [Ev, Data]), + {keep_state, Data, [{reply,From,ok}]}; + +state_dereg_net_initiated_wait_swm_asa(state_timeout, swm_asa_timeout, _Data) -> + {stop, normal}. diff --git a/src/conv.erl b/src/conv.erl index 1a15a3c..0c08a4d 100644 --- a/src/conv.erl +++ b/src/conv.erl @@ -40,7 +40,7 @@
-export([ip_to_bin/1, bin_to_ip/1]). -export([cause_gtp2gsup/1]). --export([dia_rc_to_gsup_cause/1]). +-export([dia_rc_success/1, dia_rc_to_gsup_cause/1]). -export([gtp2_paa_to_epdg_eua/1, epdg_eua_to_gsup_pdp_address/1]). -export([nai_to_imsi/1]).
@@ -92,6 +92,10 @@ -define(DIAMETER_ERROR_EQUIPMENT_UNKNOWN, 5422). -define(DIAMETER_ERROR_UNKOWN_SERVING_NODE, 5423).
+dia_rc_success(#epdg_dia_rc{result_code = 2001}) -> ok; +dia_rc_success(#epdg_dia_rc{result_code = 2002}) -> ok; +dia_rc_success(_) -> invalid_result_code. + -spec dia_rc_to_gsup_cause(#epdg_dia_rc{}) -> non_neg_integer(). dia_rc_to_gsup_cause(#epdg_dia_rc{result_code = 2001}) -> 0; dia_rc_to_gsup_cause(#epdg_dia_rc{result_code = 2002}) -> 0; diff --git a/src/epdg_diameter_swm.erl b/src/epdg_diameter_swm.erl index c2babe3..ef70b9c 100644 --- a/src/epdg_diameter_swm.erl +++ b/src/epdg_diameter_swm.erl @@ -19,8 +19,10 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2]). -export([code_change/3, terminate/2]).
--export([auth_request/4, auth_compl_request/2, session_termination_request/1]). --export([auth_response/2, auth_compl_response/2, session_termination_answer/2]). +-export([auth_request/4, auth_compl_request/2, + session_termination_request/1, abort_session_answer/1]). +-export([auth_response/2, auth_compl_response/2, + session_termination_answer/2, abort_session_request/1]).
-define(SERVER, ?MODULE).
@@ -72,6 +74,17 @@ _ -> Result end.
+% 3GPP TS 29.273 7.1.2.4 +abort_session_answer(Imsi) -> + % In Diameter we use Imsi as strings, as done by diameter module. + ImsiStr = binary_to_list(Imsi), + Result = gen_server:call(?SERVER, {asa, ImsiStr}), + case Result of + {ok, _Mar} -> + ok; + _ -> Result + end. + handle_call({epdg_auth_req, Imsi, PdpTypeNr, Apn, EAP}, {Pid, _Tag} = _From, State0) -> % we yet don't implement the Diameter SWm interface on the wire, we process the call internally: {_Sess, State1} = find_or_new_swm_session(Imsi, Pid, State0), @@ -98,6 +111,17 @@ undefined -> Reply = {error,unknown_imsi} end, + {reply, Reply, State}; + +handle_call({asa, Imsi}, _From, State) -> + % we yet don't implement the Diameter SWm interface on the wire, we process the call internally: + Sess = find_swm_session_by_imsi(Imsi, State), + case Sess of + #swm_session{imsi = Imsi} -> + Reply = aaa_diameter_swm:abort_session_answer(Imsi); + undefined -> + Reply = {error,unknown_imsi} + end, {reply, Reply, State}.
handle_cast({epdg_auth_resp, Imsi, Result}, State) -> @@ -130,6 +154,16 @@ end, {noreply, State};
+handle_cast({asr, Imsi}, State) -> + Sess = find_swm_session_by_imsi(Imsi, State), + case Sess of + #swm_session{imsi = Imsi} -> + epdg_ue_fsm:received_swm_abort_session_request(Sess#swm_session.pid); + undefined -> + error_logger:error_report(["unknown swm_session", {module, ?MODULE}, {imsi, Imsi}, {state, State}]) + end, + {noreply, State}; + handle_cast(Info, S) -> error_logger:error_report(["unknown handle_cast", {module, ?MODULE}, {info, Info}, {state, S}]), {noreply, S}. @@ -160,6 +194,10 @@ session_termination_answer(Imsi, Result) -> ok = gen_server:cast(?SERVER, {sta, Imsi, Result}).
+% Rx SWm Diameter ASR: +abort_session_request(Imsi) -> + ok = gen_server:cast(?SERVER, {asr, Imsi}). + %% ------------------------------------------------------------------ %% Internal Function Definitions %% ------------------------------------------------------------------ diff --git a/src/epdg_ue_fsm.erl b/src/epdg_ue_fsm.erl index a422bea..7b565b3 100644 --- a/src/epdg_ue_fsm.erl +++ b/src/epdg_ue_fsm.erl @@ -43,11 +43,13 @@ -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]). +-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_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).
@@ -144,6 +146,15 @@ {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 @@ -360,6 +371,14 @@ 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}]}; @@ -418,3 +437,36 @@ 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}.