pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35676?usp=email )

Change subject: Implement UE-initiated Detach
......................................................................

Implement UE-initiated Detach

This commit is a first step towards implementing the full procedure. It
implements handling at the GSUP CEAI interface and operating on the
attached PGW to delete the session. No work towards the HSS from AAA
server now from PGW to the AAA is done yet.

Change-Id: I2e922f76c2fa601c5f61fa23d6df5fb62c3e133d
---
M .gitignore
A include/gtp_utils.hrl
A src/conv.erl
M src/epdg_gtpc_s2b.erl
M src/gsup_server.erl
M src/gtp_utils.erl
M src/ue_fsm.erl
7 files changed, 423 insertions(+), 10 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, approved




diff --git a/.gitignore b/.gitignore
index 08ae348..253618b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 _build/
-include/
+include/diameter_*
 log/

 *.beam
diff --git a/include/gtp_utils.hrl b/include/gtp_utils.hrl
new file mode 100644
index 0000000..453efb0
--- /dev/null
+++ b/include/gtp_utils.hrl
@@ -0,0 +1,113 @@
+% (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.
+%
+-hrl_name('gtp_utils.hrl').
+
+-define(GTP2_CAUSE_RESERVED, 1).
+-define(GTP2_CAUSE_LOCAL_DETACH, 2).
+-define(GTP2_CAUSE_COMPLETE_DETACH, 3).
+-define(GTP2_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP, 4).
+-define(GTP2_CAUSE_ISR_DEACTIVATION, 5).
+-define(GTP2_CAUSE_ERROR_INDICATION_RECEIVED_FROM_RNC_ENODEB_S4_SGSN, 6).
+-define(GTP2_CAUSE_IMSI_DETACH_ONLY, 7).
+-define(GTP2_CAUSE_REACTIVATION_REQUESTED, 8).
+-define(GTP2_CAUSE_PDN_RECONNECTION_TO_THIS_APN_DISALLOWED, 9).
+-define(GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP, 10).
+-define(GTP2_CAUSE_PDN_CONNECTION_INACTIVITY_TIMER_EXPIRES, 11).
+-define(GTP2_CAUSE_PGW_NOT_RESPONDING, 12).
+-define(GTP2_CAUSE_NETWORK_FAILURE, 13).
+-define(GTP2_CAUSE_QOS_PARAMETER_MISMATCH, 14).
+-define(GTP2_CAUSE_REQUEST_ACCEPTED, 16).
+-define(GTP2_CAUSE_REQUEST_ACCEPTED_PARTIALLY, 17).
+-define(GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_NETWORK_PREFERENCE, 18).
+-define(GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_SINGLE_ADDRESS_BEARER_ONLY, 19).
+-define(GTP2_CAUSE_CONTEXT_NOT_FOUND, 64).
+-define(GTP2_CAUSE_INVALID_MESSAGE_FORMAT, 65).
+-define(GTP2_CAUSE_VERSION_NOT_SUPPORTED_BY_NEXT_PEER, 66).
+-define(GTP2_CAUSE_INVALID_LENGTH, 67).
+-define(GTP2_CAUSE_SERVICE_NOT_SUPPORTED, 68).
+-define(GTP2_CAUSE_MANDATORY_IE_INCORRECT, 69).
+-define(GTP2_CAUSE_MANDATORY_IE_MISSING, 70).
+-define(GTP2_CAUSE_SYSTEM_FAILURE, 72).
+-define(GTP2_CAUSE_NO_RESOURCES_AVAILABLE, 73).
+-define(GTP2_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION, 74).
+-define(GTP2_CAUSE_SYNTACTIC_ERROR_IN_THE_TFT_OPERATION, 75).
+-define(GTP2_CAUSE_SEMANTIC_ERRORS_IN_PACKET_FILTER, 76).
+-define(GTP2_CAUSE_SYNTACTIC_ERRORS_IN_PACKET_FILTER, 77).
+-define(GTP2_CAUSE_MISSING_OR_UNKNOWN_APN, 78).
+-define(GTP2_CAUSE_GRE_KEY_NOT_FOUND, 80).
+-define(GTP2_CAUSE_RELOCATION_FAILURE, 81).
+-define(GTP2_CAUSE_DENIED_IN_RAT, 82).
+-define(GTP2_CAUSE_PREFERRED_PDN_TYPE_NOT_SUPPORTED, 83).
+-define(GTP2_CAUSE_ALL_DYNAMIC_ADDRESSES_ARE_OCCUPIED, 84).
+-define(GTP2_CAUSE_UE_CONTEXT_WITHOUT_TFT_ALREADY_ACTIVATED, 85).
+-define(GTP2_CAUSE_PROTOCOL_TYPE_NOT_SUPPORTED, 86).
+-define(GTP2_CAUSE_UE_NOT_RESPONDING, 87).
+-define(GTP2_CAUSE_UE_REFUSES, 88).
+-define(GTP2_CAUSE_SERVICE_DENIED, 89).
+-define(GTP2_CAUSE_UNABLE_TO_PAGE_UE, 90).
+-define(GTP2_CAUSE_NO_MEMORY_AVAILABLE, 91).
+-define(GTP2_CAUSE_USER_AUTHENTICATION_FAILED, 92).
+-define(GTP2_CAUSE_APN_ACCESS_DENIED___NO_SUBSCRIPTION, 93).
+-define(GTP2_CAUSE_REQUEST_REJECTED, 94).
+-define(GTP2_CAUSE_P_TMSI_SIGNATURE_MISMATCH, 95).
+-define(GTP2_CAUSE_IMSI_IMEI_NOT_KNOWN, 96).
+-define(GTP2_CAUSE_SEMANTIC_ERROR_IN_THE_TAD_OPERATION, 97).
+-define(GTP2_CAUSE_SYNTACTIC_ERROR_IN_THE_TAD_OPERATION, 98).
+-define(GTP2_CAUSE_REMOTE_PEER_NOT_RESPONDING, 100).
+-define(GTP2_CAUSE_COLLISION_WITH_NETWORK_INITIATED_REQUEST, 101).
+-define(GTP2_CAUSE_UNABLE_TO_PAGE_UE_DUE_TO_SUSPENSION, 102).
+-define(GTP2_CAUSE_CONDITIONAL_IE_MISSING, 103).
+-define(GTP2_CAUSE_APN_RESTRICTION_TYPE_INCOMPATIBLE_WITH_CURRENTLY_ACTIVE_PDN_CONNECTION,
 104).
+-define(GTP2_CAUSE_INVALID_OVERALL_LENGTH_OF_THE_TRIGGERED_RESPONSE_MESSAGE_AND_A_PIGGYBACKED_INITIAL_MESSAGE,
 105).
+-define(GTP2_CAUSE_DATA_FORWARDING_NOT_SUPPORTED, 106).
+-define(GTP2_CAUSE_INVALID_REPLY_FROM_REMOTE_PEER, 107).
+-define(GTP2_CAUSE_FALLBACK_TO_GTPV1, 108).
+-define(GTP2_CAUSE_INVALID_PEER, 109).
+-define(GTP2_CAUSE_TEMPORARILY_REJECTED_DUE_TO_HANDOVER_TAU_RAU_PROCEDURE_IN_PROGRESS,
 110).
+-define(GTP2_CAUSE_MODIFICATIONS_NOT_LIMITED_TO_S1_U_BEARERS, 111).
+-define(GTP2_CAUSE_REQUEST_REJECTED_FOR_A_PMIPV6_REASON, 112).
+-define(GTP2_CAUSE_APN_CONGESTION, 113).
+-define(GTP2_CAUSE_BEARER_HANDLING_NOT_SUPPORTED, 114).
+-define(GTP2_CAUSE_UE_ALREADY_RE_ATTACHED, 115).
+-define(GTP2_CAUSE_MULTIPLE_PDN_CONNECTIONS_FOR_A_GIVEN_APN_NOT_ALLOWED, 116).
+-define(GTP2_CAUSE_TARGET_ACCESS_RESTRICTED_FOR_THE_SUBSCRIBER, 117).
+-define(GTP2_CAUSE_MME_SGSN_REFUSES_DUE_TO_VPLMN_POLICY, 119).
+-define(GTP2_CAUSE_GTP_C_ENTITY_CONGESTION, 120).
+-define(GTP2_CAUSE_LATE_OVERLAPPING_REQUEST, 121).
+-define(GTP2_CAUSE_TIMED_OUT_REQUEST, 122).
+-define(GTP2_CAUSE_UE_IS_TEMPORARILY_NOT_REACHABLE_DUE_TO_POWER_SAVING, 123).
+-define(GTP2_CAUSE_RELOCATION_FAILURE_DUE_TO_NAS_MESSAGE_REDIRECTION, 124).
+-define(GTP2_CAUSE_UE_NOT_AUTHORISED_BY_OCS_OR_EXTERNAL_AAA_SERVER, 125).
+-define(GTP2_CAUSE_MULTIPLE_ACCESSES_TO_A_PDN_CONNECTION_NOT_ALLOWED, 126).
+-define(GTP2_CAUSE_REQUEST_REJECTED_DUE_TO_UE_CAPABILITY, 127).
+-define(GTP2_CAUSE_S1_U_PATH_FAILURE, 128).
+-define(GTP2_CAUSE_5GC_NOT_ALLOWED, 129).
\ No newline at end of file
diff --git a/src/conv.erl b/src/conv.erl
new file mode 100644
index 0000000..30365cc
--- /dev/null
+++ b/src/conv.erl
@@ -0,0 +1,53 @@
+% Conversion tools
+% (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(conv).
+-author('Pau Espin Pedrol <pes...@sysmocom.de>').
+
+-include_lib("osmo_gsup/include/gsup_protocol.hrl").
+-include_lib("gtp_utils.hrl").
+
+-export([cause_gtp2gsup/1]).
+
+-spec cause_gtp2gsup(integer()) -> integer().
+
+cause_gtp2gsup(?GTP2_CAUSE_REQUEST_ACCEPTED) -> 0;
+cause_gtp2gsup(?GTP2_CAUSE_IMSI_IMEI_NOT_KNOWN) -> ?GSUP_CAUSE_IMSI_UNKNOWN;
+cause_gtp2gsup(?GTP2_CAUSE_INVALID_PEER) -> ?GSUP_CAUSE_ILLEGAL_MS;
+cause_gtp2gsup(?GTP2_CAUSE_DENIED_IN_RAT) -> ?GSUP_CAUSE_GPRS_NOTALLOWED;
+cause_gtp2gsup(?GTP2_CAUSE_NETWORK_FAILURE) -> ?GSUP_CAUSE_NET_FAIL;
+cause_gtp2gsup(?GTP2_CAUSE_APN_CONGESTION) -> ?GSUP_CAUSE_CONGESTION;
+cause_gtp2gsup(?GTP2_CAUSE_GTP_C_ENTITY_CONGESTION) -> ?GSUP_CAUSE_CONGESTION;
+cause_gtp2gsup(?GTP2_CAUSE_USER_AUTHENTICATION_FAILED) -> 
?GSUP_CAUSE_GSM_AUTH_UNACCEPT;
+cause_gtp2gsup(?GTP2_CAUSE_MANDATORY_IE_INCORRECT) -> 
?GSUP_CAUSE_INV_MAND_INFO;
+cause_gtp2gsup(?GTP2_CAUSE_MANDATORY_IE_MISSING) -> ?GSUP_CAUSE_INV_MAND_INFO;
+cause_gtp2gsup(_) -> ?GSUP_CAUSE_PROTO_ERR_UNSPEC.
diff --git a/src/epdg_gtpc_s2b.erl b/src/epdg_gtpc_s2b.erl
index fc41351..7e3dd6e 100644
--- a/src/epdg_gtpc_s2b.erl
+++ b/src/epdg_gtpc_s2b.erl
@@ -48,7 +48,7 @@
 %% gen_server Function Exports
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
 -export([code_change/3]).
--export([create_session_req/1]).
+-export([create_session_req/1, delete_session_req/1]).

 %% Application Definitions
 -define(SERVER, ?MODULE).
@@ -139,13 +139,28 @@
 create_session_req(Imsi) ->
     gen_server:call(?SERVER, {gtpc_create_session_req, {Imsi}}).

+delete_session_req(Imsi) ->
+    gen_server:call(?SERVER, {gtpc_delete_session_req, {Imsi}}).
+
 handle_call({gtpc_create_session_req, {Imsi}}, {Pid, _Tag} = _From, State0) ->
     {Sess0, State1} = find_or_new_gtp_session(Imsi, Pid, State0),
     Req = gen_create_session_request(Sess0, State1),
     %TODO: increment State.seq_no.
     tx_gtp(Req, State1),
     lager:debug("Waiting for CreateSessionResponse~n", []),
-    {reply, ok, State1}.
+    {reply, ok, State1};
+
+handle_call({gtpc_delete_session_req, {Imsi}}, _From, State) ->
+    Sess = find_gtp_session_by_imsi(Imsi, State),
+    case Sess of
+        #gtp_session{imsi = Imsi} ->
+            Req = gen_delete_session_request(Sess, State),
+            %TODO: increment State.seq_no.
+            tx_gtp(Req, State),
+            {reply, ok, State};
+        undefined ->
+            {reply, {error, imsi_unknown}, State}
+    end.

 %% @callback gen_server
 handle_cast(stop, State) ->
@@ -276,6 +291,18 @@
             {noreply, State1}
         end;

+rx_gtp(Resp = #gtp{version = v2, type = delete_session_response}, State0) ->
+    Sess = find_gtp_session_by_local_teic(Resp#gtp.tei, State0),
+    case Sess of
+        undefined ->
+            lager:error("Rx unknown TEI ~p: ~p~n", [Resp#gtp.tei, Resp]),
+            {noreply, State0};
+        Sess ->
+            State1 = delete_gtp_session(Sess, State0),
+            ue_fsm:received_gtpc_delete_session_response(Sess#gtp_session.pid, 
Resp),
+            {noreply, State1}
+        end;
+
 rx_gtp(Req = #gtp{version = v2, type = delete_bearer_request}, State) ->
     Sess = find_gtp_session_by_local_teic(Req#gtp.tei, State),
     case Sess of
@@ -340,6 +367,22 @@
           ],
     #gtp{version = v2, type = create_session_request, tei = 0, seq_no = SeqNo, 
ie = IEs}.

+%% 7.2.9 Delete Session Request
+gen_delete_session_request(#gtp_session{remote_control_tei = RemoteCtlTEI,
+                                        bearer = Bearer},
+                           #gtp_state{laddr = LocalAddr,
+                                      seq_no = SeqNo}) ->
+    IEs = [#v2_eps_bearer_id{eps_bearer_id = Bearer#gtp_bearer.ebi},
+           #v2_fully_qualified_tunnel_endpoint_identifier{
+               instance = Bearer#gtp_bearer.ebi,
+               interface_type = 30, %% "S2b ePDG GTP-C"
+               key = Bearer#gtp_bearer.local_data_tei,
+               ipv4 = gtp_utils:ip_to_bin(LocalAddr)
+           }
+    ],
+    #gtp{version = v2, type = delete_session_request, tei = RemoteCtlTEI, 
seq_no = SeqNo, ie = IEs}.
+
+
 gen_delete_bearer_response(Req = #gtp{version = v2, type = 
delete_bearer_request},
                            Sess = #gtp_session{remote_control_tei = 
RemoteCtlTEI},
                            GtpCause,
diff --git a/src/gsup_server.erl b/src/gsup_server.erl
index 30e8864..cebcc0f 100644
--- a/src/gsup_server.erl
+++ b/src/gsup_server.erl
@@ -62,7 +62,7 @@

 -export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
 -export([code_change/3, terminate/2]).
--export([auth_response/2, lu_response/2, tunnel_response/2]).
+-export([auth_response/2, lu_response/2, tunnel_response/2, 
purge_ms_response/2]).

 % TODO: -spec dia_sip2gsup('SIP-Auth-Data-Item'()) -> #'GSUPAuthTuple'{}.
 dia_sip2gsup(#'SIP-Auth-Data-Item'{'SIP-Authenticate' = [Authenticate], 
'SIP-Authorization' = [Authorization],
@@ -182,6 +182,25 @@
        tx_gsup(Socket, Resp),
        {noreply, State};

+handle_cast({purge_ms_response, {Imsi, Result}}, State0) ->
+       lager:info("purge_ms_response for ~p: ~p~n", [Imsi, Result]),
+       Socket = State0#gsups_state.socket,
+       case Result of
+               ok ->
+                       Resp = #{message_type => purge_ms_res,
+                               imsi => Imsi,
+                               freeze_p_tmsi => true
+                               };
+               {error, GsupCause} ->
+                       Resp = #{message_type => purge_ms_err,
+                               imsi => Imsi,
+                               cause => GsupCause
+                               }
+       end,
+       tx_gsup(Socket, Resp),
+       State1 = delete_gsups_ue(Imsi, State0),
+       {noreply, State1};
+
 handle_cast(Info, S) ->
        error_logger:error_report(["unknown handle_cast", {module, ?MODULE}, 
{info, Info}, {state, S}]),
        {noreply, S}.
@@ -269,6 +288,31 @@
        end,
        {noreply, State};

+% Purge MS / trigger the delete of session to the PGW
+handle_info({ipa, Socket, ?IPAC_PROTO_EXT_GSUP, GsupMsgRx = #{message_type := 
purge_ms_req, imsi := Imsi}}, State) ->
+       lager:info("GSUP: Rx ~p~n", [GsupMsgRx]),
+       UE = find_gsups_ue_by_imsi(Imsi, State),
+       case UE of
+       #gsups_ue{imsi = Imsi} ->
+               case ue_fsm:purge_ms_request(UE#gsups_ue.pid) of
+               ok ->   ok;
+               _  ->   Resp = #{message_type => purge_ms_err,
+                               imsi => Imsi,
+                               message_class => 5,
+                               cause => ?GSUP_CAUSE_NET_FAIL
+                       },
+                       tx_gsup(Socket, Resp)
+               end;
+       undefined ->
+               Resp = #{message_type => purge_ms_err,
+                        imsi => Imsi,
+                        message_class => 5,
+                        cause => ?GSUP_CAUSE_IMSI_UNKNOWN
+               },
+               tx_gsup(Socket, Resp)
+       end,
+       {noreply, State};
+
 handle_info(Info, S) ->
        error_logger:error_report(["unknown handle_info", {module, ?MODULE}, 
{info, Info}, {state, S}]),
        {noreply, S}.
@@ -291,6 +335,10 @@
        lager:info("tunnel_response(~p): ~p~n", [Imsi, Result]),
        gen_server:cast(?SERVER, {tunnel_response, {Imsi, Result}}).

+purge_ms_response(Imsi, Result) ->
+       lager:info("purge_ms_response(~p): ~p~n", [Imsi, Result]),
+       gen_server:cast(?SERVER, {purge_ms_response, {Imsi, Result}}).
+
 %% ------------------------------------------------------------------
 %% Internal Function Definitions
 %% ------------------------------------------------------------------
@@ -322,4 +370,8 @@
                {UE, State};
            undefined ->
                new_gsups_ue(Imsi, State)
-       end.
\ No newline at end of file
+       end.
+
+delete_gsups_ue(Imsi, State) ->
+       SetRemoved = sets:del_element(Imsi, State#gsups_state.ues),
+       State#gsups_state{ues = SetRemoved}.
\ No newline at end of file
diff --git a/src/gtp_utils.erl b/src/gtp_utils.erl
index 85f69ef..eb0a23a 100644
--- a/src/gtp_utils.erl
+++ b/src/gtp_utils.erl
@@ -35,7 +35,7 @@
 -module(gtp_utils).
 -author('Alexander Couzens <lyn...@fe80.eu>').

--export([ip_to_bin/1, plmn_to_bin/3]).
+-export([ip_to_bin/1, plmn_to_bin/3, enum_v2_cause/1]).

 % ergw_aaa/src/ergw_aaa_3gpp_dict.erl
 % under GPLv2+
@@ -52,3 +52,84 @@
     MCC = iolist_to_binary(io_lib:format("~3..0b", [CC])),
     MNC = iolist_to_binary(io_lib:format("~*..0b", [NCSize, NC])),
     {MCC, MNC}.
+
+enum_v2_cause(reserved) -> 1;
+enum_v2_cause(local_detach) -> 2;
+enum_v2_cause(complete_detach) -> 3;
+enum_v2_cause(rat_changed_from_3gpp_to_non_3gpp) -> 4;
+enum_v2_cause(isr_deactivation) -> 5;
+enum_v2_cause(error_indication_received_from_rnc_enodeb_s4_sgsn) -> 6;
+enum_v2_cause(imsi_detach_only) -> 7;
+enum_v2_cause(reactivation_requested) -> 8;
+enum_v2_cause(pdn_reconnection_to_this_apn_disallowed) -> 9;
+enum_v2_cause(access_changed_from_non_3gpp_to_3gpp) -> 10;
+enum_v2_cause(pdn_connection_inactivity_timer_expires) -> 11;
+enum_v2_cause(pgw_not_responding) -> 12;
+enum_v2_cause(network_failure) -> 13;
+enum_v2_cause(qos_parameter_mismatch) -> 14;
+enum_v2_cause(request_accepted) -> 16;
+enum_v2_cause(request_accepted_partially) -> 17;
+enum_v2_cause(new_pdn_type_due_to_network_preference) -> 18;
+enum_v2_cause(new_pdn_type_due_to_single_address_bearer_only) -> 19;
+enum_v2_cause(context_not_found) -> 64;
+enum_v2_cause(invalid_message_format) -> 65;
+enum_v2_cause(version_not_supported_by_next_peer) -> 66;
+enum_v2_cause(invalid_length) -> 67;
+enum_v2_cause(service_not_supported) -> 68;
+enum_v2_cause(mandatory_ie_incorrect) -> 69;
+enum_v2_cause(mandatory_ie_missing) -> 70;
+enum_v2_cause(system_failure) -> 72;
+enum_v2_cause(no_resources_available) -> 73;
+enum_v2_cause(semantic_error_in_the_tft_operation) -> 74;
+enum_v2_cause(syntactic_error_in_the_tft_operation) -> 75;
+enum_v2_cause(semantic_errors_in_packet_filter) -> 76;
+enum_v2_cause(syntactic_errors_in_packet_filter) -> 77;
+enum_v2_cause(missing_or_unknown_apn) -> 78;
+enum_v2_cause(gre_key_not_found) -> 80;
+enum_v2_cause(relocation_failure) -> 81;
+enum_v2_cause(denied_in_rat) -> 82;
+enum_v2_cause(preferred_pdn_type_not_supported) -> 83;
+enum_v2_cause(all_dynamic_addresses_are_occupied) -> 84;
+enum_v2_cause(ue_context_without_tft_already_activated) -> 85;
+enum_v2_cause(protocol_type_not_supported) -> 86;
+enum_v2_cause(ue_not_responding) -> 87;
+enum_v2_cause(ue_refuses) -> 88;
+enum_v2_cause(service_denied) -> 89;
+enum_v2_cause(unable_to_page_ue) -> 90;
+enum_v2_cause(no_memory_available) -> 91;
+enum_v2_cause(user_authentication_failed) -> 92;
+enum_v2_cause(apn_access_denied___no_subscription) -> 93;
+enum_v2_cause(request_rejected) -> 94;
+enum_v2_cause(p_tmsi_signature_mismatch) -> 95;
+enum_v2_cause(imsi_imei_not_known) -> 96;
+enum_v2_cause(semantic_error_in_the_tad_operation) -> 97;
+enum_v2_cause(syntactic_error_in_the_tad_operation) -> 98;
+enum_v2_cause(remote_peer_not_responding) -> 100;
+enum_v2_cause(collision_with_network_initiated_request) -> 101;
+enum_v2_cause(unable_to_page_ue_due_to_suspension) -> 102;
+enum_v2_cause(conditional_ie_missing) -> 103;
+enum_v2_cause(apn_restriction_type_incompatible_with_currently_active_pdn_connection)
 -> 104;
+enum_v2_cause(invalid_overall_length_of_the_triggered_response_message_and_a_piggybacked_initial_message)
 -> 105;
+enum_v2_cause(data_forwarding_not_supported) -> 106;
+enum_v2_cause(invalid_reply_from_remote_peer) -> 107;
+enum_v2_cause(fallback_to_gtpv1) -> 108;
+enum_v2_cause(invalid_peer) -> 109;
+enum_v2_cause(temporarily_rejected_due_to_handover_tau_rau_procedure_in_progress)
 -> 110;
+enum_v2_cause(modifications_not_limited_to_s1_u_bearers) -> 111;
+enum_v2_cause(request_rejected_for_a_pmipv6_reason) -> 112;
+enum_v2_cause(apn_congestion) -> 113;
+enum_v2_cause(bearer_handling_not_supported) -> 114;
+enum_v2_cause(ue_already_re_attached) -> 115;
+enum_v2_cause(multiple_pdn_connections_for_a_given_apn_not_allowed) -> 116;
+enum_v2_cause(target_access_restricted_for_the_subscriber) -> 117;
+enum_v2_cause(mme_sgsn_refuses_due_to_vplmn_policy) -> 119;
+enum_v2_cause(gtp_c_entity_congestion) -> 120;
+enum_v2_cause(late_overlapping_request) -> 121;
+enum_v2_cause(timed_out_request) -> 122;
+enum_v2_cause(ue_is_temporarily_not_reachable_due_to_power_saving) -> 123;
+enum_v2_cause(relocation_failure_due_to_nas_message_redirection) -> 124;
+enum_v2_cause(ue_not_authorised_by_ocs_or_external_aaa_server) -> 125;
+enum_v2_cause(multiple_accesses_to_a_pdn_connection_not_allowed) -> 126;
+enum_v2_cause(request_rejected_due_to_ue_capability) -> 127;
+enum_v2_cause(s1_u_path_failure) -> 128;
+enum_v2_cause('5gc_not_allowed') -> 129.
diff --git a/src/ue_fsm.erl b/src/ue_fsm.erl
index c0b8872..f17dfdc 100644
--- a/src/ue_fsm.erl
+++ b/src/ue_fsm.erl
@@ -34,10 +34,14 @@
 -behaviour(gen_statem).
 -define(NAME, ue_fsm).

+-include_lib("osmo_gsup/include/gsup_protocol.hrl").
+-include_lib("gtplib/include/gtp_packet.hrl").
+
 -export([start_link/1]).
 -export([init/1,callback_mode/0,terminate/3]).
--export([auth_request/1, lu_request/1, tunnel_request/1, 
received_gtpc_create_session_response/2]).
--export([state_new/3,state_authenticated/3]).
+-export([auth_request/1, lu_request/1, tunnel_request/1, purge_ms_request/1]).
+-export([received_gtpc_create_session_response/2, 
received_gtpc_delete_session_response/2]).
+-export([state_new/3,state_authenticated/3, state_wait_delete_session_resp/3]).

 -record(ue_fsm_data, {
         imsi
@@ -75,6 +79,15 @@
                 {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_gtpc_create_session_response(Pid, Msg) ->
         lager:info("ue_fsm received_gtpc_create_session_response ~p~n", [Msg]),
         try
@@ -84,6 +97,23 @@
                 {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.
+
+%% ------------------------------------------------------------------
+%% Internal helpers
+%% ------------------------------------------------------------------
+
+%% ------------------------------------------------------------------
+%% gen_statem Function Definitions
+%% ------------------------------------------------------------------
+
 init(Imsi) ->
         lager:info("ue_fsm init(~p)~n", [Imsi]),
         Data = #ue_fsm_data{imsi = Imsi},
@@ -105,7 +135,11 @@
                         {next_state, state_authenticated, Data, 
[{reply,From,ok}]};
                {error, Err} ->
                         {stop_and_reply, Err, Data, [{reply,From,{error,Err}}]}
-       end.
+       end;
+
+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, Data, [{reply,From,ok}]}.

 state_authenticated({call, From}, lu_request, Data) ->
         lager:info("ue_fsm state_authenticated event=lu_request, ~p~n", 
[Data]),
@@ -128,10 +162,33 @@
         gsup_server:tunnel_response(Data#ue_fsm_data.imsi, Result),
         {keep_state, 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]),
+        case epdg_gtpc_s2b:delete_session_req(Data#ue_fsm_data.imsi) of
+        ok -> {next_state, state_wait_delete_session_resp, Data, 
[{reply,From,ok}]};
+        {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]}
+        end;
+
 state_authenticated({call, From}, _Whatever, Data) ->
         lager:error("ue_fsm state_authenticated: Unexpected call event, ~p~n", 
[Data]),
         {keep_state, Data, [{reply,From,ok}]};

 state_authenticated(cast, _Whatever, Data) ->
         lager:error("ue_fsm state_authenticated: Unexpected cast event, ~p~n", 
[Data]),
-        {keep_state, Data}.
\ No newline at end of file
+        {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]),
+        case GsupCause of
+        0 -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, ok);
+        _ -> gsup_server:purge_ms_response(Data#ue_fsm_data.imsi, {error, 
GsupCause})
+        end,
+        {keep_state, Data, [{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}}]}.

--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35676?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: I2e922f76c2fa601c5f61fa23d6df5fb62c3e133d
Gerrit-Change-Number: 35676
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pes...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to