fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/37463?usp=email )
Change subject: {sctp,s1ap}_proxy: employ E-RAB FSMs ......................................................................
{sctp,s1ap}_proxy: employ E-RAB FSMs
Change-Id: Ibb7e25ab3adbadd7fd85e9cb22e0136c6ca133cf --- M src/s1ap_proxy.erl M src/sctp_proxy.erl 2 files changed, 71 insertions(+), 6 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/63/37463/1
diff --git a/src/s1ap_proxy.erl b/src/s1ap_proxy.erl index eaa7dfd..f1a2726 100644 --- a/src/s1ap_proxy.erl +++ b/src/s1ap_proxy.erl @@ -37,6 +37,7 @@ -export([init/0, deinit/1, handle_pdu/2, + handle_exit/2, encode_pdu/1, decode_pdu/1]).
@@ -48,7 +49,7 @@ -include("S1AP-Constants.hrl").
--record(proxy_state, { }). +-record(proxy_state, {erabs :: dict:dict()}).
-type proxy_state() :: #proxy_state{}.
@@ -59,7 +60,7 @@ %% Initialize per-connection data -spec init() -> proxy_state(). init() -> - #proxy_state{}. + #proxy_state{erabs = dict:new()}.
%% De-initialize per-connection data @@ -81,6 +82,13 @@ end.
+%% Handle an exit event +-spec handle_exit(pid(), proxy_state()) -> proxy_state(). +handle_exit(Pid, #proxy_state{erabs = ERABs} = S) -> + Fun = fun(_Key, Val) -> Val =/= Pid end, + S#proxy_state{erabs = dict:filter(Fun, ERABs)}. + + %% ------------------------------------------------------------------ %% private API %% ------------------------------------------------------------------ @@ -99,6 +107,18 @@ 'S1AP-PDU-Descriptions':decode('S1AP-PDU', Data).
+%% Decode TEID from binary to integer +-spec decode_teid(binary()) -> non_neg_integer(). +decode_teid(<< TEID:32/big >>) -> + TEID. + + +%% Encode TEID from integer to binary +-spec encode_teid(non_neg_integer()) -> binary(). +encode_teid(TEID) when is_integer(TEID) -> + << TEID:32/big >>. + + %% Helper function for handle_pdu/3. %% Attempt to encode a new (modified) S1AP PDU, %% return a new binary() on success or Data on error. @@ -189,10 +209,16 @@ handle_ies(Content, ?'id-E-RABToBeSetupItemBearerSUReq', S);
handle_ie(#'ProtocolIE-Field'{id = ?'id-E-RABToBeSetupItemBearerSUReq', - value = Content}, S) -> + value = Content}, S0) -> %% eNB -> MME direction: we pass our MME facing local address TLA = transp_layer_addr(mme_loc_addr), - {Content#'E-RABToBeSetupItemBearerSUReq'{transportLayerAddress = TLA}, S}; + %% start and register an E-RAB FSM + #'E-RABToBeSetupItemBearerSUReq'{'e-RAB-ID' = ERABId, + 'gTP-TEID' = TEID_FromAcc} = Content, + {Pid, S1} = erab_fsm_start_reg(ERABId, S0), + {ok, TEID_ToCore} = erab_fsm:erab_setup_req(Pid, decode_teid(TEID_FromAcc)), + {Content#'E-RABToBeSetupItemBearerSUReq'{transportLayerAddress = TLA, + 'gTP-TEID' = encode_teid(TEID_ToCore)}, S1};
%% E-RAB SETUP RESPONSE related IEs handle_ie(#'ProtocolIE-Field'{id = ?'id-E-RABSetupListBearerSURes', @@ -201,10 +227,22 @@ handle_ies(Content, ?'id-E-RABSetupItemBearerSURes', S);
handle_ie(#'ProtocolIE-Field'{id = ?'id-E-RABSetupItemBearerSURes', - value = Content}, S) -> + value = C0}, S) -> %% MME -> eNB direction: we pass our eNB facing local address TLA = transp_layer_addr(s1gw_bind_addr), - {Content#'E-RABSetupItemBearerSURes'{transportLayerAddress = TLA}, S}; + %% poke E-RAB FSM + #'E-RABSetupItemBearerSURes'{'e-RAB-ID' = ERABId, + 'gTP-TEID' = TEID_FromCore} = C0, + C1 = case dict:find(ERABId, S#proxy_state.erabs) of + {ok, Pid} -> + {ok, TEID_ToAcc} = erab_fsm:erab_setup_rsp(Pid, decode_teid(TEID_FromCore)), + C0#'E-RABSetupItemBearerSURes'{transportLayerAddress = TLA, + 'gTP-TEID' = encode_teid(TEID_ToAcc)}; + error -> + ?LOG_ERROR("E-RAB-ID ~p is not registered", [ERABId]), + C0#'E-RABSetupItemBearerSURes'{transportLayerAddress = TLA} + end, + {C1, S};
%% E-RAB MODIFICATION INDICATION related IEs handle_ie(#'ProtocolIE-Field'{id = ?'id-E-RABToBeModifiedListBearerModInd', @@ -287,4 +325,15 @@ %% sadly, there exists inet:ntoa/1, but not inet:aton/1 list_to_binary(tuple_to_list(Addr)).
+ +-spec erab_fsm_start_reg(non_neg_integer(), proxy_state()) -> {pid(), proxy_state()}. +erab_fsm_start_reg(RABId, S) -> + {ok, Pid} = erab_fsm:start_link(RABId), %% TODO: add {eNB,MME}-UE-ID + {Pid, erab_fsm_reg(RABId, Pid, S)}. + + +-spec erab_fsm_reg(non_neg_integer(), pid(), proxy_state()) -> proxy_state(). +erab_fsm_reg(RABId, Pid, #proxy_state{erabs = ERABs} = S) -> + S#proxy_state{erabs = dict:store(RABId, Pid, ERABs)}. + %% vim:set ts=4 sw=4 et: diff --git a/src/sctp_proxy.erl b/src/sctp_proxy.erl index 148e00a..1d8d305 100644 --- a/src/sctp_proxy.erl +++ b/src/sctp_proxy.erl @@ -167,6 +167,13 @@ sctp_server:send_data(EnbAid, NewData), {keep_state, S#{priv := NewPriv}};
+%% Handle termination events of the child processes +connected(info, {'EXIT', Pid, Reason}, + #{priv := Priv} = S) -> + ?LOG_DEBUG("Child process ~p terminated with reason ~p", [Pid, Reason]), + NewPriv = s1ap_proxy:handle_exit(Pid, Priv), + {keep_state, S#{priv := NewPriv}}; + %% Catch-all for other kinds of SCTP events connected(info, {sctp, _Socket, MmeAddr, MmePort, {AncData, Data}}, S) ->