pespin has uploaded this change for review.

View Change

Forward PGW Address HSS->AAA->ePDG

Use subscriber information provided by AAA & HSS regarding PDN-GW
address when creating the S2b session.

Related: OS#6384
Change-Id: I83a68271ee6548e0e32fc9f0cab385bad5852388
---
M src/aaa_diameter_swm.erl
M src/aaa_diameter_swx_cb.erl
M src/aaa_ue_fsm.erl
M src/epdg_gtpc_s2b.erl
M src/epdg_ue_fsm.erl
5 files changed, 122 insertions(+), 27 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-epdg refs/changes/58/36158/1
diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl
index 7fdc247..0e3fa45 100644
--- a/src/aaa_diameter_swm.erl
+++ b/src/aaa_diameter_swm.erl
@@ -67,7 +67,8 @@
#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})
+ RC_USER_UNKNOWN=5030,
+ epdg_diameter_swm:auth_compl_response(Imsi, {error, RC_USER_UNKNOWN})
end,
{noreply, State};

diff --git a/src/aaa_diameter_swx_cb.erl b/src/aaa_diameter_swx_cb.erl
index bf4a79e..5dd00ef 100644
--- a/src/aaa_diameter_swx_cb.erl
+++ b/src/aaa_diameter_swx_cb.erl
@@ -77,7 +77,18 @@
#'SAR'{'Server-Assignment-Type' = SAType} = Request,
% Retrieve fields from answer:
#'SAA'{'Result-Code' = [ResultCode]} = Msg,
- aaa_ue_fsm:ev_rx_swx_saa(ReqPid, {SAType, ResultCode}),
+ case result_code_success(ResultCode) of
+ ok ->
+ #'SAA'{'Non-3GPP-User-Data' = N3UA} = Msg,
+ PGWAddresses = parse_pgw_addr_from_N3UA(N3UA),
+ case PGWAddresses of
+ undefined -> ResInfo = #{};
+ _ -> ResInfo = maps:put(pgw_address_list, PGWAddresses, #{})
+ end,
+ aaa_ue_fsm:ev_rx_swx_saa(ReqPid, {ok, SAType, ResInfo});
+ _ ->
+ aaa_ue_fsm:ev_rx_swx_saa(ReqPid, {error, SAType, ResultCode})
+ end,
{ok, Msg}.
handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) ->
lager:info("SWx Rx ~p: ~p~n", [Peer, Msg]),
@@ -101,3 +112,33 @@
%% handle_request/3
handle_request(_Packet, _SvcName, _Peer) ->
erlang:error({unexpected, ?MODULE, ?LINE}).
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+result_code_success(2001) -> ok;
+result_code_success(2002) -> ok;
+result_code_success(_) -> invalid_result_code.
+
+parse_pgw_addr_from_MIP6_Agent_Info([]) ->
+ undefined;
+parse_pgw_addr_from_MIP6_Agent_Info([AgentInfo]) ->
+ #'MIP6-Agent-Info'{'MIP-Home-Agent-Address' = AgentAddrOpt} = AgentInfo,
+ case AgentAddrOpt of
+ [] -> undefined;
+ Res -> Res
+ end.
+parse_pgw_addr_from_APN_Configuration([]) ->
+ undefined;
+parse_pgw_addr_from_APN_Configuration([Head | Tail] = _ApnConfigs) ->
+ #'APN-Configuration'{'MIP6-Agent-Info' = AgentInfoOpt} = Head,
+ case parse_pgw_addr_from_MIP6_Agent_Info(AgentInfoOpt) of
+ undefined -> parse_pgw_addr_from_APN_Configuration(Tail);
+ Res -> Res
+ end.
+parse_pgw_addr_from_N3UA([]) ->
+ undefined;
+parse_pgw_addr_from_N3UA([N3UA]) ->
+ #'Non-3GPP-User-Data'{'APN-Configuration' = ApnConfigs} = N3UA,
+ parse_pgw_addr_from_APN_Configuration(ApnConfigs).
\ No newline at end of file
diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl
index 7f70005..fd39061 100644
--- a/src/aaa_ue_fsm.erl
+++ b/src/aaa_ue_fsm.erl
@@ -102,10 +102,10 @@
{error, Err}
end.

-ev_rx_swx_saa(Pid, {SAType, ResultCode}) ->
+ev_rx_swx_saa(Pid, Result) ->
lager:info("ue_fsm ev_rx_swx_saa~n", []),
try
- gen_statem:call(Pid, {rx_swx_saa, SAType, ResultCode})
+ gen_statem:call(Pid, {rx_swx_saa, Result})
catch
exit:Err ->
{error, Err}
@@ -181,11 +181,16 @@
state_wait_swx_saa(enter, _OldState, Data) ->
{keep_state, 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, ResultCode}),
- % TODO: don't transit if SAS returned error code.
- {next_state, state_authenticated, Data, [{reply,From,ok}]}.
+state_wait_swx_saa({call, From}, {rx_swx_saa, Result}, Data) ->
+ lager:info("ue_fsm state_wait_swx_saa event=rx_swx_saa ~p, ~p~n", [Result, Data]),
+ case Result of
+ {error, _SAType, ResultCode} ->
+ aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {error, ResultCode}),
+ {next_state, state_new, Data, [{reply,From,ok}]};
+ {ok, _SAType, ResInfo} ->
+ aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, ResInfo}),
+ {next_state, state_authenticated, Data, [{reply,From,ok}]}
+ end.

state_authenticated(enter, _OldState, Data) ->
% Mark ePDG session as active:
@@ -256,7 +261,11 @@
state_authenticated_wait_swx_saa(enter, _OldState, Data) ->
{keep_state, Data};

-state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, SAType, ResultCode}, Data) ->
+state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, Result}, Data) ->
+ case Result of
+ {error, SAType, ResultCode} -> ResultCode;
+ {ok, SAType, _ResInfo} -> ResultCode = 2001
+ end,
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_PGW_UPDATE' ->
diff --git a/src/epdg_gtpc_s2b.erl b/src/epdg_gtpc_s2b.erl
index b0a34bd..a8a42a2 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/3, delete_session_req/1]).
+-export([create_session_req/4, delete_session_req/1]).

%% Application Definitions
-define(SERVER, ?MODULE).
@@ -88,6 +88,8 @@
imsi :: binary(),
pid :: pid(),
apn :: binary(),
+ raddr_str :: string(),
+ raddr :: inet:ip_address(),
ue_ip :: inet:ip_address(),
local_control_tei = 0 :: non_neg_integer(),
remote_control_tei = 0 :: non_neg_integer(),
@@ -142,15 +144,21 @@
lager:error("GTPv2C UDP socket open error: ~w~n", [Reason])
end.

-create_session_req(Imsi, Apn, APCO) ->
- gen_server:call(?SERVER, {gtpc_create_session_req, {Imsi, Apn, APCO}}).
+create_session_req(Imsi, Apn, APCO, PGWAddrCandidateList) ->
+ gen_server:call(?SERVER, {gtpc_create_session_req, {Imsi, Apn, APCO, PGWAddrCandidateList}}).

delete_session_req(Imsi) ->
gen_server:call(?SERVER, {gtpc_delete_session_req, {Imsi}}).

-handle_call({gtpc_create_session_req, {Imsi, Apn, APCO}}, {Pid, _Tag} = _From, State0) ->
+handle_call({gtpc_create_session_req, {Imsi, Apn, APCO, PGWAddrCandidateList}}, {Pid, _Tag} = _From, State0) ->
+ RemoteAddrStr = pick_gtpc_remote_address(PGWAddrCandidateList, State0),
+ lager:debug("Selected PGW Remote Address ~p~n", [RemoteAddrStr]),
+ {ok, RemoteAddrInet} = inet_parse:address(RemoteAddrStr),
{Sess0, State1} = find_or_new_gtp_session(Imsi,
- #gtp_session{pid = Pid, apn = list_to_binary(Apn)},
+ #gtp_session{pid = Pid,
+ apn = list_to_binary(Apn),
+ raddr_str = RemoteAddrInet,
+ raddr = RemoteAddrInet},
State0),
Req = gen_create_session_request(Sess0, APCO, State1),
tx_gtp(Req, State1),
@@ -352,6 +360,16 @@
find_unused_local_teid(State, State#gtp_state.next_local_data_tei,
dec_tei(State#gtp_state.next_local_data_tei)).

+pick_gtpc_remote_address(PGWAddrCandidateList, State) ->
+ case PGWAddrCandidateList of
+ [] ->
+ %% Pick default address from configuration:
+ State#gtp_state .raddr_str;
+ [Head|_Tail] ->
+ % TODO: pick a compatible address with .laddr from PGWAddrCandidateList is exists.
+ Head
+ end.
+
%% connect/2
connect(Name, {Socket, RemoteAddr, RemotePort}) ->
lager:info("~s connecting to IP ~s port ~p~n", [Name, RemoteAddr, RemotePort]),
diff --git a/src/epdg_ue_fsm.erl b/src/epdg_ue_fsm.erl
index 291df26..c6358fd 100644
--- a/src/epdg_ue_fsm.erl
+++ b/src/epdg_ue_fsm.erl
@@ -53,10 +53,11 @@

-record(ue_fsm_data, {
imsi,
- apn = "internet" :: string(),
- tun_pdp_ctx :: epdg_tun_pdp_ctx,
- tear_down_gsup_needed = false :: boolean(), %% need to send GSUP PurgeMSResp after STR+STA?
- tear_down_gsup_cause = 0 :: integer()
+ apn = "internet" :: string(),
+ pgw_rem_addr_list = [] :: list(),
+ tun_pdp_ctx :: epdg_tun_pdp_ctx,
+ tear_down_gsup_needed = false :: boolean(), %% need to send GSUP PurgeMSResp after STR+STA?
+ tear_down_gsup_cause = 0 :: integer()
}).

get_server_name_by_imsi(Imsi) ->
@@ -236,13 +237,22 @@
lager:info("ue_fsm state_authenticating event=lu_request, ~p, ~p~n", [Result, Data]),
% Rx "GSUP CEAI LU Req" is our way of saying Rx "Swm Diameter-EAP REQ (DER) with EAP AVP containing successuful auth":
case Result of
- {ok, _} ->
- Ret = ok;
- {error, Err} ->
- Ret = {error, Err}
- end,
- gsup_server:lu_response(Data#ue_fsm_data.imsi, Ret),
- {next_state, state_authenticated, Data, [{reply,From,Ret}]}.
+ {ok, ResInfo} ->
+ % Store PGW Remote address if AAA/HSS signalled them to us:
+ case maps:find(pdp_info_list, ResInfo) of
+ error ->
+ Data1 = Data;
+ PGWAddrCandidateList ->
+ Data1 = Data#ue_fsm_data{pgw_rem_addr_list = PGWAddrCandidateList}
+ end,
+ Ret = ok,
+ gsup_server:lu_response(Data1#ue_fsm_data.imsi, Ret),
+ {next_state, state_authenticated, Data1, [{reply,From,Ret}]};
+ {error, Err} ->
+ Ret = {error, Err},
+ gsup_server:lu_response(Data#ue_fsm_data.imsi, Ret),
+ {next_state, state_new, Data, [{reply,From,Ret}]}
+ end.

state_authenticated(enter, _OldState, Data) ->
{keep_state, Data};
@@ -253,7 +263,10 @@

state_authenticated({call, From}, {tunnel_request, PCO}, Data) ->
lager:info("ue_fsm state_authenticated event=tunnel_request, ~p~n", [Data]),
- epdg_gtpc_s2b:create_session_req(Data#ue_fsm_data.imsi, Data#ue_fsm_data.apn, PCO),
+ epdg_gtpc_s2b:create_session_req(Data#ue_fsm_data.imsi,
+ Data#ue_fsm_data.apn,
+ PCO,
+ Data#ue_fsm_data.pgw_rem_addr_list),
{next_state, state_wait_create_session_resp, Data, [{reply,From,ok}]};

state_authenticated({call, From}, purge_ms_request, Data) ->

To view, visit change 36158. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: erlang/osmo-epdg
Gerrit-Branch: master
Gerrit-Change-Id: I83a68271ee6548e0e32fc9f0cab385bad5852388
Gerrit-Change-Number: 36158
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-MessageType: newchange