pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35760?usp=email )
Change subject: Send SAR(DEREGISTRATION) to HSS when all sessions are terminated ......................................................................
Send SAR(DEREGISTRATION) to HSS when all sessions are terminated
Change-Id: I62eba8ef916d52964df4135d1031f3950b6818a2 --- 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 5 files changed, 157 insertions(+), 21 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-epdg refs/changes/60/35760/1
diff --git a/src/aaa_diameter_s6b.erl b/src/aaa_diameter_s6b.erl index 2de479c..2792b6a 100644 --- a/src/aaa_diameter_s6b.erl +++ b/src/aaa_diameter_s6b.erl @@ -51,7 +51,7 @@ -export([code_change/3]). -export([multimedia_auth_request/6]). -export([server_assignment_request/3]). --export([tx_aa_answer/2]). +-export([tx_aa_answer/2, tx_st_answer/2]). -export([test/0, test/1]).
%% Diameter Application Definitions @@ -151,6 +151,10 @@ % handle_request(AAR) was spawned into its own process, and it's blocked waiting for AAA: Pid ! {aaa, ResultCode}.
+tx_st_answer(Pid, ResultCode) -> + % handle_request(STR) was spawned into its own process, and it's blocked waiting for STA: + Pid ! {sta, ResultCode}. + result_code_success(2001) -> ok; result_code_success(2002) -> ok; result_code_success(_) -> invalid_result_code. diff --git a/src/aaa_diameter_s6b_cb.erl b/src/aaa_diameter_s6b_cb.erl index b03bce1..339f735 100644 --- a/src/aaa_diameter_s6b_cb.erl +++ b/src/aaa_diameter_s6b_cb.erl @@ -86,10 +86,30 @@ #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, #'STR'{'Session-Id' = SessionId, 'Auth-Application-Id' = _AuthAppId, - 'User-Name' = _UserNameOpt} = Req, + 'Termination-Cause' = _TermCause, + 'User-Name' = [UserName]} = Req, + Result = aaa_diameter_swm:get_ue_fsm_by_imsi(UserName), + case Result of + {ok, Pid} -> + case aaa_ue_fsm:ev_rx_s6b_str(Pid) of + ok -> + lager:debug("Waiting for S6b STA~n", []), + receive + {sta, ResultCode} -> lager:debug("Rx STA with ResultCode=~p~n", [ResultCode]) + end; + {ok, DiaRC} when is_integer(DiaRC) -> + ResultCode = DiaRC; + {error, Err} when is_integer(Err) -> + ResultCode = Err; + {error, _} -> + ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' + end; + _ -> lager:error("Error looking up FSM for IMSI~n", [UserName]), + ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' + end, % 3GPP TS 29.273 9.2.2.3.2 Session-Termination-Answer (STA) Command: Resp = #'STA'{'Session-Id' = SessionId, - 'Result-Code' = 2001, + 'Result-Code' = ResultCode, 'Origin-Host' = OH, 'Origin-Realm' = OR}, lager:info("S6b Tx to ~p: ~p~n", [Caps, Resp]), diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl index 68aa054..9458383 100644 --- a/src/aaa_diameter_swm.erl +++ b/src/aaa_diameter_swm.erl @@ -4,7 +4,7 @@ -module(aaa_diameter_swm). -behaviour(gen_server).
--include_lib("diameter_3gpp_ts29_273_swx.hrl"). +-include_lib("diameter_3gpp_ts29_273.hrl").
-record(swm_state, { table_id, % ets table id, @@ -22,7 +22,7 @@ -export([get_ue_fsm_by_imsi/1]).
-export([auth_request/1, auth_compl_request/2, session_termination_request/1]). --export([auth_response/2, auth_compl_response/2]). +-export([auth_response/2, auth_compl_response/2, session_termination_answer/2]).
-define(SERVER, ?MODULE).
@@ -45,6 +45,9 @@ auth_compl_response(Imsi, Result) -> _Result = gen_server:call(?SERVER, {epdg_auth_compl_resp, Imsi, Result}).
+session_termination_answer(Imsi, Result) -> + _Result = gen_server:call(?SERVER, {sta, Imsi, Result}). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Rx from emulated SWm wire: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -73,7 +76,21 @@ {noreply, State};
handle_cast({str, Imsi}, State) -> - ok = epdg_diameter_swm:session_termination_answer(Imsi, 2001), + Sess = find_swm_session_by_imsi(Imsi, State), + case Sess of + #swm_session{} -> + case aaa_ue_fsm:ev_rx_swm_str(Sess#swm_session.pid) of + ok -> ok; % Answering delayed due to SAR+SAA towards HSS. + {ok, DiaRC} when is_integer(DiaRC) -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, DiaRC); + {error, Err} when is_integer(Err) -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, Err); + {error, _} -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED') + end; + undefined -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED') + end, {noreply, State};
handle_cast(Info, S) -> @@ -102,6 +119,10 @@ epdg_diameter_swm:auth_compl_response(Imsi, Result), {reply, ok, State};
+handle_call({sta, Imsi, DiaRC}, _From, State) -> + epdg_diameter_swm:session_termination_answer(Imsi, DiaRC), + {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 a7b9b7c..472f1d4 100644 --- a/src/aaa_diameter_swx_cb.erl +++ b/src/aaa_diameter_swx_cb.erl @@ -71,10 +71,13 @@ lager:info("SWx Rx MAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), aaa_ue_fsm:ev_rx_swx_maa(ReqPid, Msg), {ok, Msg}; -handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'SAA') -> +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'SAA') -> lager:info("SWx Rx SAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), + % Recover fields from originating request: + #'SAR'{'Server-Assignment-Type' = SAType} = Request, + % Retrieve fields from answer: #'SAA'{'Result-Code' = [ResultCode]} = Msg, - aaa_ue_fsm:ev_rx_swx_saa(ReqPid, ResultCode), + aaa_ue_fsm:ev_rx_swx_saa(ReqPid, {SAType, ResultCode}), {ok, Msg}. handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) -> lager:info("SWx Rx ~p: ~p~n", [Peer, Msg]), diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl index e214540..c043cdb 100644 --- a/src/aaa_ue_fsm.erl +++ b/src/aaa_ue_fsm.erl @@ -35,15 +35,18 @@ -define(NAME, aaa_ue_fsm).
-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter_3gpp_ts29_229.hrl"). -include_lib("diameter_3gpp_ts29_273_s6b.hrl").
-export([start_link/1]). -export([init/1,callback_mode/0,terminate/3]). --export([ev_swm_auth_req/1, ev_swm_auth_compl/2, ev_rx_swx_maa/2, ev_rx_swx_saa/2, ev_rx_s6b_aar/2]). +-export([ev_swm_auth_req/1, 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]).
-record(ue_fsm_data, { imsi = unknown :: binary(), + apn :: string(), epdg_sess_active = false :: boolean(), pgw_sess_active = false :: boolean(), s6b_resp_pid :: pid() @@ -72,6 +75,15 @@ {error, Err} end.
+ev_rx_swm_str(Pid) -> + lager:info("ue_fsm ev_rx_swm_str~n", []), + try + gen_statem:call(Pid, rx_swm_str) + catch + exit:Err -> + {error, Err} + end. + ev_rx_swx_maa(Pid, MAA) -> lager:info("ue_fsm ev_rx_swx_maa~n", []), try @@ -81,10 +93,10 @@ {error, Err} end.
-ev_rx_swx_saa(Pid, ResultCode) -> +ev_rx_swx_saa(Pid, {SAType, ResultCode}) -> lager:info("ue_fsm ev_rx_swx_saa~n", []), try - gen_statem:call(Pid, {rx_swx_saa, ResultCode}) + gen_statem:call(Pid, {rx_swx_saa, SAType, ResultCode}) catch exit:Err -> {error, Err} @@ -99,6 +111,15 @@ {error, Err} end.
+ev_rx_s6b_str(Pid) -> + lager:info("ue_fsm ev_rx_s6b_str: ~p~n", []), + try + gen_statem:call(Pid, rx_s6b_str) + catch + exit:Err -> + {error, Err} + end. + %% ------------------------------------------------------------------ %% Internal helpers %% ------------------------------------------------------------------ @@ -151,9 +172,9 @@ state_wait_swx_saa(enter, _OldState, Data) -> {keep_state, Data};
-state_wait_swx_saa({call, From}, {rx_swx_saa, SAA}, Data) -> +state_wait_swx_saa({call, From}, {rx_swx_saa, _SAType, ResultCode}, Data) -> lager:info("ue_fsm state_wait_swx_saa event=rx_swx_saa, ~p~n", [Data]), - aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, SAA}), + aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, ResultCode}), % TODO: don't transit if SAS returned error code. {next_state, state_authenticated, Data, [{reply,From,ok}]}.
@@ -164,12 +185,57 @@
state_authenticated({call, {Pid, _Tag} = From}, {rx_s6b_aar, Apn}, Data) -> lager:info("ue_fsm state_authenticated event=rx_s6b_aar Apn=~p, ~p~n", [Apn, Data]), - case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, 1, Apn) of - ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid}, + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_REGISTRATION', + Apn) of + ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid, apn = Apn}, {next_state, state_authenticated_wait_swx_saa, Data1, [{reply,From,ok}]}; {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]} end;
+state_authenticated({call, From}, rx_swm_str, Data) -> + lager:info("ue_fsm state_authenticated event=rx_swm_str, ~p~n", [Data]), + case {Data#ue_fsm_data.epdg_sess_active, Data#ue_fsm_data.pgw_sess_active} of + {false, _} -> %% The SWm session is not active... + 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", []), + 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 + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION', + Data#ue_fsm_data.apn) of + ok -> {next_state, state_authenticated_wait_swx_saa, Data, [{reply,From,ok}]}; + {error, _Err} -> + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]} + end + end; + +state_authenticated({call, {Pid, _Tag} = From}, rx_s6b_str, Data) -> + lager:info("ue_fsm state_authenticated event=rx_s6b_str, ~p~n", [Data]), + case {Data#ue_fsm_data.pgw_sess_active, Data#ue_fsm_data.epdg_sess_active} of + {false, _} -> %% The S6b session is not active... + 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_s6b_str: ePDG session still active, skip updating the HSS~n", []), + Data1 = Data#ue_fsm_data{pgw_sess_active = false}, + {keep_state, Data1, [{reply,From,{ok, 2001}}]}; + {true, false} -> %% All sessions will now be gone, trigger SAR Type=USER_DEREGISTRATION + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION', + Data#ue_fsm_data.apn) of + ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid}, + {next_state, state_authenticated_wait_swx_saa, Data1, [{reply,From,ok}]}; + {error, _Err} -> + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]} + end + end; + state_authenticated({call, From}, _Whatever, Data) -> lager:info("ue_fsm state_authenticated event=purge_ms_request, ~p~n", [Data]), {keep_state, Data, [{reply,From,ok}]}. @@ -177,9 +243,22 @@ state_authenticated_wait_swx_saa(enter, _OldState, Data) -> {keep_state, Data};
-state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, ResultCode}, Data) -> - lager:info("ue_fsm state_authenticated_wait_swx_saa event=rx_swx_saa ResulCode=~p, ~p~n", [ResultCode, Data]), - aaa_diameter_s6b:tx_aa_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), - Data1 = Data#ue_fsm_data{s6b_resp_pid = undefined}, - {next_state, state_authenticated, Data1, [{reply,From,ok}]}. - +state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, SAType, ResultCode}, Data) -> + lager:info("ue_fsm state_authenticated_wait_swx_saa event=rx_swx_saa SAType=~p ResulCode=~p, ~p~n", [SAType, ResultCode, Data]), + case SAType of + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_REGISTRATION' -> + aaa_diameter_s6b:tx_aa_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), + Data1 = Data#ue_fsm_data{pgw_sess_active = true, s6b_resp_pid = undefined}, + {next_state, state_authenticated, Data1, [{reply,From,ok}]}; + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION' -> + case Data#ue_fsm_data.s6b_resp_pid of + undefined -> %% SWm initiated + aaa_diameter_swm:session_termination_answer(Data#ue_fsm_data.imsi, ResultCode), + Data1 = Data#ue_fsm_data{epdg_sess_active = false}, + {next_state, state_new, Data1, [{reply,From,ok}]}; + _ -> %% S6b initiated + aaa_diameter_s6b:tx_st_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), + 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