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 <pes...@sysmocom.de>
Gerrit-MessageType: newchange

Reply via email to