pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/36158?usp=email )
Change subject: Forward PGW Address HSS->AAA->ePDG ......................................................................
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) ->