pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35759?usp=email )
Change subject: AAA-Server: Process S6b, SWx requests async through new aaa_ue_fsm
......................................................................
AAA-Server: Process S6b, SWx requests async through new aaa_ue_fsm
This will allow keeping per-UE session state, and for instance send a
SAR(USER_DEREGISTRATION) towards HSS when all sessions from all
interfaces (s6b, SWm) are terminated.
Change-Id: I78ebda4679d0a2f3ecede94598e74b20c2ff8836
---
M src/aaa_diameter_s6b.erl
M src/aaa_diameter_s6b_cb.erl
M src/aaa_diameter_swm.erl
M src/aaa_diameter_swx.erl
M src/aaa_diameter_swx_cb.erl
A src/aaa_ue_fsm.erl
6 files changed, 343 insertions(+), 72 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-epdg refs/changes/59/35759/1
diff --git a/src/aaa_diameter_s6b.erl b/src/aaa_diameter_s6b.erl
index 59b9679..2de479c 100644
--- a/src/aaa_diameter_s6b.erl
+++ b/src/aaa_diameter_s6b.erl
@@ -40,8 +40,8 @@
-behaviour(gen_server).
--include_lib("diameter_3gpp_ts29_273_s6b.hrl").
-include_lib("diameter/include/diameter_gen_base_rfc6733.hrl").
+-include_lib("diameter_3gpp_ts29_273_s6b.hrl").
%% API Function Exports
-export([start_link/0]).
@@ -51,6 +51,7 @@
-export([code_change/3]).
-export([multimedia_auth_request/6]).
-export([server_assignment_request/3]).
+-export([tx_aa_answer/2]).
-export([test/0, test/1]).
%% Diameter Application Definitions
@@ -146,6 +147,10 @@
gen_server:call(?SERVER,
{sar, {IMSI, Type, APN}}).
+tx_aa_answer(Pid, ResultCode) ->
+ % handle_request(AAR) was spawned into its own process, and it's blocked waiting
for AAA:
+ Pid ! {aaa, 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 ccfcaff..b03bce1 100644
--- a/src/aaa_diameter_s6b_cb.erl
+++ b/src/aaa_diameter_s6b_cb.erl
@@ -23,17 +23,17 @@
State.
%% pick_peer/4
-pick_peer([_Peer | _], _, _SvcName, _State) ->
- ?UNEXPECTED.
+pick_peer([Peer | _], _, _SvcName, _State) ->
+ {ok, Peer}.
%% prepare_request/3
-
-prepare_request(_, _SvcName, _Peer) ->
- ?UNEXPECTED.
+prepare_request(_Req, _SvcName, _Peer) ->
+ lager:error("Unexpected prepare_request(): ~p~n", [_Req]),
+ ?UNEXPECTED.
%% prepare_retransmit/3
-prepare_retransmit(_Packet, _SvcName, _Peer) ->
- ?UNEXPECTED.
+prepare_retransmit(Packet, SvcName, Peer) ->
+ prepare_request(Packet, SvcName, Peer).
%% handle_answer/4
@@ -42,12 +42,12 @@
%% the former case, return in the latter.
handle_answer(_Packet, _Request, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?UNEXPECTED.
%% handle_error/4
handle_error(Reason, Request, _SvcName, _Peer) when is_list(Request) ->
lager:error("Request error: ~p~n", [Reason]),
- ?UNEXPECTED.
+ ?UNEXPECTED.
% 3GPP TS 29.273 9.1.2.2
handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when
is_record(Req, 'AAR') ->
@@ -59,21 +59,25 @@
'Auth-Request-Type' = AuthReqType,
'User-Name' = [UserName],
'Service-Selection' = [Apn]} = Req,
- Result = aaa_diameter_swx:server_assignment_request(UserName, 1, Apn),
+ Result = aaa_diameter_swm:get_ue_fsm_by_imsi(UserName),
case Result of
- {ok, _} ->
- ResultCode = 2001;
- {error, _Err} ->
- ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED'
+ {ok, Pid} ->
+ ok = aaa_ue_fsm:ev_rx_s6b_aar(Pid, Apn),
+ lager:debug("Waiting for S6b AAA~n", []),
+ receive
+ {aaa, ResultCode} -> lager:debug("Rx AAA with ResultCode=~p~n",
[ResultCode])
+ end;
+ _ -> lager:error("Error looking up FSM for IMSI~n", [UserName]),
+ ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED'
end,
- Resp = #'AAA'{'Session-Id'=SessionId,
+ Resp = #'AAA'{'Session-Id'= SessionId,
'Auth-Application-Id' = AuthAppId,
'Auth-Request-Type' = AuthReqType,
'Result-Code' = ResultCode,
'Origin-Host' = OH,
'Origin-Realm' = OR},
lager:info("S6b Tx to ~p: ~p~n", [Caps, Resp]),
- {reply, Resp};
+ {reply, Resp};
% 3GPP TS 29.273 9.2.2.3.1 Session-Termination-Request (STR) Command:
handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when
is_record(Req, 'STR') ->
diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl
index a3e5132..68aa054 100644
--- a/src/aaa_diameter_swm.erl
+++ b/src/aaa_diameter_swm.erl
@@ -7,14 +7,22 @@
-include_lib("diameter_3gpp_ts29_273_swx.hrl").
-record(swm_state, {
- table_id % ets table id
+ table_id, % ets table id,
+ ues = sets:new()
}).
+-record(swm_session, {
+ imsi :: binary(),
+ pid :: pid()
+ }).
+
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
-export([code_change/3, terminate/2]).
+-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]).
-define(SERVER, ?MODULE).
@@ -25,7 +33,21 @@
TableId = ets:new(auth_req, [bag, named_table]),
{ok, #swm_state{table_id = TableId}}.
+get_ue_fsm_by_imsi(Imsi) ->
+ _Result = gen_server:call(?SERVER, {get_ue_fsm_by_imsi, Imsi}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Tx over emulated SWm wire:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+auth_response(Imsi, Result) ->
+ _Result = gen_server:call(?SERVER, {epdg_auth_resp, Imsi, Result}).
+
+auth_compl_response(Imsi, Result) ->
+ _Result = gen_server:call(?SERVER, {epdg_auth_compl_resp, Imsi, Result}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Rx from emulated SWm wire:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
auth_request(Imsi) ->
gen_server:cast(?SERVER, {epdg_auth_req, Imsi}).
@@ -35,25 +57,18 @@
session_termination_request(Imsi) ->
gen_server:cast(?SERVER, {str, Imsi}).
-handle_cast({epdg_auth_req, Imsi}, State) ->
- % request the diameter code for a tuple
- CKey = [],
- IntegrityKey = [],
- Result = aaa_diameter_swx:multimedia_auth_request(Imsi, 1, "EAP-AKA", 1, CKey,
IntegrityKey),
- case Result of
- {ok, _MAA} -> epdg_diameter_swm:auth_response(Imsi, Result);
- {error, _Err} -> epdg_diameter_swm:auth_response(Imsi, Result);
- _ -> epdg_diameter_swm:auth_response(Imsi, {error, unknown})
- end,
- {noreply, State};
+handle_cast({epdg_auth_req, Imsi}, State0) ->
+ {Sess, State1} = find_or_new_swm_session(Imsi, State0),
+ aaa_ue_fsm:ev_swm_auth_req(Sess#swm_session.pid),
+ {noreply, State1};
handle_cast({epdg_auth_compl_req, Imsi, Apn}, State) ->
- % request the diameter code for a tuple
- Result = aaa_diameter_swx:server_assignment_request(Imsi, 1, Apn),
- case Result of
- {ok, _SAA} -> epdg_diameter_swm:auth_compl_response(Imsi, Result);
- {error, _Err} -> epdg_diameter_swm:auth_compl_response(Imsi, Result);
- _ -> epdg_diameter_swm:auth_compl_response(Imsi, {error, unknown})
+ Sess = find_swm_session_by_imsi(Imsi, State),
+ case Sess of
+ #swm_session{imsi = Imsi} ->
+ aaa_ue_fsm:ev_swm_auth_compl(Sess#swm_session.pid, Apn);
+ undefined ->
+ epdg_diameter_swm:auth_compl_response(Imsi, {error, imsi_unknown})
end,
{noreply, State};
@@ -69,6 +84,24 @@
error_logger:error_report(["unknown handle_info", {module, ?MODULE}, {info,
Info}, {state, S}]),
{noreply, S}.
+handle_call({get_ue_fsm_by_imsi, Imsi}, _From, State) ->
+ Sess = find_swm_session_by_imsi(Imsi, State),
+ lager:debug("find_swm_session_by_imsi(~p) returned ~p~n", [Imsi, Sess]),
+ case Sess of
+ #swm_session{} ->
+ {reply, {ok ,Sess#swm_session.pid}, State};
+ undefined ->
+ {reply, {error, imsi_unknown}, State}
+ end;
+
+handle_call({epdg_auth_resp, Imsi, Result}, _From, State) ->
+ epdg_diameter_swm:auth_response(Imsi, Result),
+ {reply, ok, State};
+
+handle_call({epdg_auth_compl_resp, Imsi, Result}, _From, State) ->
+ epdg_diameter_swm:auth_compl_response(Imsi, Result),
+ {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}.
@@ -81,3 +114,35 @@
terminate(Reason, _S) ->
lager:info("terminating ~p with reason ~p~n", [?MODULE, Reason]).
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+new_swm_session(Imsi, State) ->
+ {ok, Pid} = aaa_ue_fsm:start_link(Imsi),
+ UE = #swm_session{imsi = Imsi, pid = Pid},
+ NewSt = State#swm_state{ues = sets:add_element(UE, State#swm_state.ues)},
+ {UE, NewSt}.
+
+% returns swm_session if found, undefined if not
+find_swm_session_by_imsi(Imsi, State) ->
+ sets:fold(
+ fun(UEsIt = #swm_session{imsi = Imsi}, _AccIn) -> UEsIt;
+ (_, AccIn) -> AccIn
+ end,
+ undefined,
+ State#swm_state.ues).
+
+find_or_new_swm_session(Imsi, State) ->
+ UE = find_swm_session_by_imsi(Imsi, State),
+ case UE of
+ #swm_session{imsi = Imsi} ->
+ {UE, State};
+ undefined ->
+ new_swm_session(Imsi, State)
+ end.
+
+delete_swm_session(Imsi, State) ->
+ SetRemoved = sets:del_element(Imsi, State#swm_state.ues),
+ State#swm_state{ues = SetRemoved}.
\ No newline at end of file
diff --git a/src/aaa_diameter_swx.erl b/src/aaa_diameter_swx.erl
index 411c000..1db5809 100644
--- a/src/aaa_diameter_swx.erl
+++ b/src/aaa_diameter_swx.erl
@@ -181,7 +181,7 @@
parse_saa(Saa) ->
{unknown_err, []}.
-handle_call({mar, {IMSI, NumAuthItems, AuthScheme, RAT, CKey, IntegrityKey}}, _From,
State) ->
+handle_call({mar, {IMSI, NumAuthItems, AuthScheme, RAT, CKey, IntegrityKey}}, {Pid, _Tag}
= _From, State) ->
SessionId = diameter:session_id(application:get_env(?ENV_APP_NAME, origin_host,
?ENV_DEFAULT_ORIG_HOST)),
MAR = #'MAR'{'Vendor-Specific-Application-Id' =
#'Vendor-Specific-Application-Id'{
'Vendor-Id' = ?VENDOR_ID_3GPP,
@@ -196,20 +196,17 @@
'SIP-Number-Auth-Items' = NumAuthItems,
'RAT-Type' = RAT
},
- Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, MAR, []),
+ Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, MAR, [{extra, [Pid]}, detach]),
case Ret of
- {ok, MAA} ->
- SuccessCode = parse_maa(MAA),
- case SuccessCode of
- {ok, _} -> {reply, {ok, MAA}, State};
- {Err, Info} -> {reply, {error, {Err, Info, MAA}}, State}
- end;
+ ok ->
+ {reply, ok, State};
{error, Err} ->
lager:error("Error: ~w~n", [Err]),
{reply, {error, Err}, State}
end;
-handle_call({sar, {IMSI, Type, APN}}, _From, State) ->
+handle_call({sar, {IMSI, Type, APN}}, {Pid, _Tag} = _From, State) ->
+ lager:debug("SWx Tx SAR Imsi=~p Type=~p APN=~p~n", [IMSI, Type, APN]),
SessionId = diameter:session_id(application:get_env(?ENV_APP_NAME, origin_host,
?ENV_DEFAULT_ORIG_HOST)),
SAR = #'SAR'{'Vendor-Specific-Application-Id' =
#'Vendor-Specific-Application-Id'{
'Vendor-Id' = ?VENDOR_ID_3GPP,
@@ -220,14 +217,10 @@
'Server-Assignment-Type' = Type,
'Service-Selection' = [APN]
},
- Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, SAR, []),
+ Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, SAR, [{extra, [Pid]}, detach]),
case Ret of
- {ok, Saa} ->
- SuccessCode = parse_saa(Saa),
- case SuccessCode of
- {ok, _} -> {reply, {ok, Saa}, State};
- {Err, Info} -> {reply, {error, {Err, Info, Saa}}, State}
- end;
+ ok ->
+ {reply, ok, State};
{error, Err} ->
lager:error("Error: ~w~n", [Err]),
{reply, {error, Err}, State}
diff --git a/src/aaa_diameter_swx_cb.erl b/src/aaa_diameter_swx_cb.erl
index 215e051..a7b9b7c 100644
--- a/src/aaa_diameter_swx_cb.erl
+++ b/src/aaa_diameter_swx_cb.erl
@@ -7,13 +7,14 @@
-include_lib("diameter_3gpp_ts29_273_swx.hrl").
%% diameter callbacks
--export([peer_up/3, peer_down/3, pick_peer/4, prepare_request/3, prepare_retransmit/3,
- handle_answer/4, handle_error/4, handle_request/3]).
+-export([peer_up/3, peer_down/3, pick_peer/4, pick_peer/5, prepare_request/3,
prepare_request/4,
+ prepare_retransmit/3, prepare_retransmit/4,
+ handle_answer/4, handle_answer/5, handle_error/4, handle_request/3]).
%% peer_up/3
peer_up(_SvcName, Peer, State) ->
lager:info("Peer up: ~p~n", [Peer]),
- State.
+ State.
%% peer_down/3
peer_down(_SvcName, Peer, State) ->
@@ -23,9 +24,10 @@
%% pick_peer/4
pick_peer([Peer | _], _, _SvcName, _State) ->
{ok, Peer}.
+pick_peer([Peer | _], _, _SvcName, _State, _ExtraPars) ->
+ {ok, Peer}.
%% prepare_request/3
-
prepare_request(#diameter_packet{msg = [ T | Avps ]}, _, {_, Caps})
when is_list(Avps) ->
#diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps,
@@ -35,9 +37,9 @@
{'Origin-Realm', OR},
{'Destination-Host', [DH]},
{'Destination-Realm', DR}
- | Avps]};
+ | Avps]}.
% TODO: is there a simple way to capture all the following requests?
-prepare_request(#diameter_packet{msg = Req}, _, {_, Caps})
+prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}, _ExtraPars)
when is_record(Req, 'MAR') ->
#diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps,
Msg = Req#'MAR'{'Origin-Host' = OH,
@@ -45,36 +47,40 @@
'Destination-Host' = [DH],
'Destination-Realm' = DR},
{send, Msg};
-prepare_request(#diameter_packet{msg = Req}, _, {_, Caps})
+%% prepare_request/4
+prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}, _ExtraPars)
when is_record(Req, 'SAR') ->
#diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps,
Msg = Req#'SAR'{'Origin-Host' = OH,
'Origin-Realm' = OR,
'Destination-Host' = [DH],
'Destination-Realm' = DR},
+ lager:debug("SWx prepare_request: ~p~n", [Msg]),
{send, Msg}.
%% prepare_retransmit/3
prepare_retransmit(Packet, SvcName, Peer) ->
prepare_request(Packet, SvcName, Peer).
+%% prepare_retransmit/4
+prepare_retransmit(Packet, SvcName, Peer, ExtraPars) ->
+ prepare_request(Packet, SvcName, Peer, ExtraPars).
+
%% 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(#diameter_packet{msg = Msg, errors = []}, Request, _SvcName, _Peer)
- when is_list(Request) ->
+handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer,
ReqPid) when is_record(Msg, 'MAA') ->
+ 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)
- when is_list(Request) ->
- {error, Errors};
-
-handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, _Peer) ->
+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]),
+ #'SAA'{'Result-Code' = [ResultCode]} = Msg,
+ aaa_ue_fsm:ev_rx_swx_saa(ReqPid, ResultCode),
+ {ok, Msg}.
+handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) ->
+ lager:info("SWx Rx ~p: ~p~n", [Peer, Msg]),
{ok, Msg};
-handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, _Peer)
->
- lager:info("Some Answer res: ~p / Errors ~p ~n", [Msg, Errors]),
+handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer)
->
+ lager:info("SWx Rx ~p: ~p / Errors ~p ~n", [Peer, Msg, Errors]),
{error, Errors}.
%% handle_error/4
diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl
new file mode 100644
index 0000000..e214540
--- /dev/null
+++ b/src/aaa_ue_fsm.erl
@@ -0,0 +1,185 @@
+% 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(aaa_ue_fsm).
+-behaviour(gen_statem).
+-define(NAME, aaa_ue_fsm).
+
+-include_lib("diameter/include/diameter.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([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(),
+ epdg_sess_active = false :: boolean(),
+ pgw_sess_active = false :: boolean(),
+ s6b_resp_pid :: pid()
+ }).
+
+start_link(Imsi) ->
+ ServerName = lists:concat([?NAME, "_", binary_to_list(Imsi)]),
+ lager:info("ue_fsm start_link(~p)~n", [ServerName]),
+ gen_statem:start_link({local, list_to_atom(ServerName)}, ?MODULE, Imsi, [{debug,
[trace]}]).
+
+ev_swm_auth_req(Pid) ->
+ lager:info("ue_fsm ev_swm_auth_req~n", []),
+ try
+ gen_statem:call(Pid, swm_auth_req)
+ catch
+ exit:Err ->
+ {error, Err}
+ end.
+
+ev_swm_auth_compl(Pid, Apn) ->
+ lager:info("ue_fsm ev_swm_auth_compl~n", []),
+ try
+ gen_statem:call(Pid, {swm_auth_compl, Apn})
+ catch
+ exit:Err ->
+ {error, Err}
+ end.
+
+ev_rx_swx_maa(Pid, MAA) ->
+ lager:info("ue_fsm ev_rx_swx_maa~n", []),
+ try
+ gen_statem:call(Pid, {rx_swx_maa, MAA})
+ catch
+ exit:Err ->
+ {error, Err}
+ end.
+
+ev_rx_swx_saa(Pid, ResultCode) ->
+ lager:info("ue_fsm ev_rx_swx_saa~n", []),
+ try
+ gen_statem:call(Pid, {rx_swx_saa, ResultCode})
+ catch
+ exit:Err ->
+ {error, Err}
+ end.
+
+ev_rx_s6b_aar(Pid, Apn) ->
+ lager:info("ue_fsm ev_rx_s6b_aar: ~p~n", [Apn]),
+ try
+ gen_statem:call(Pid, {rx_s6b_aar, Apn})
+ catch
+ exit:Err ->
+ {error, Err}
+ end.
+
+%% ------------------------------------------------------------------
+%% Internal helpers
+%% ------------------------------------------------------------------
+
+%% ------------------------------------------------------------------
+%% 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]),
+ ok.
+
+state_new(enter, _OldState, Data) ->
+ {keep_state, Data};
+
+state_new({call, From}, swm_auth_req, Data) ->
+ lager:info("ue_fsm state_new event=swm_auth_req, ~p~n", [Data]),
+ % request the diameter code for a tuple
+ CKey = [],
+ IntegrityKey = [],
+ case aaa_diameter_swx:multimedia_auth_request(Data#ue_fsm_data.imsi, 1,
"EAP-AKA", 1, CKey, IntegrityKey) of
+ ok -> {next_state, state_wait_swx_maa, Data, [{reply,From,ok}]};
+ {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]}
+ end;
+
+state_new({call, From}, {swm_auth_compl, Apn}, Data) ->
+ lager:info("ue_fsm state_new event=swm_auth_compl, ~p~n", [Data]),
+ case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, 1, Apn)
of
+ ok -> {next_state, state_wait_swx_saa, Data, [{reply,From,ok}]};
+ {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]}
+ end.
+
+state_wait_swx_maa(enter, _OldState, Data) ->
+ {keep_state, Data};
+
+state_wait_swx_maa({call, From}, {rx_swx_maa, MAA}, Data) ->
+ lager:info("ue_fsm state_wait_swx_maa event=rx_swx_maa, ~p~n",
[Data]),
+ aaa_diameter_swm:auth_response(Data#ue_fsm_data.imsi, {ok, MAA}),
+ % TODO: don't transit if SAS returned error code.
+ {next_state, state_new, Data, [{reply,From,ok}]}.
+
+state_wait_swx_saa(enter, _OldState, Data) ->
+ {keep_state, Data};
+
+state_wait_swx_saa({call, From}, {rx_swx_saa, SAA}, 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}),
+ % TODO: don't transit if SAS returned error code.
+ {next_state, state_authenticated, Data, [{reply,From,ok}]}.
+
+state_authenticated(enter, _OldState, Data) ->
+ % Mark ePDG session as active:
+ Data1 = Data#ue_fsm_data{epdg_sess_active = true},
+ {keep_state, Data1};
+
+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},
+ {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}, _Whatever, Data) ->
+ lager:info("ue_fsm state_authenticated event=purge_ms_request, ~p~n",
[Data]),
+ {keep_state, Data, [{reply,From,ok}]}.
+
+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}]}.
+
--
To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35759?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: erlang/osmo-epdg
Gerrit-Branch: master
Gerrit-Change-Id: I78ebda4679d0a2f3ecede94598e74b20c2ff8836
Gerrit-Change-Number: 35759
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: newchange