pespin has submitted this change. (
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/34896?usp=email )
Change subject: s2b: Implement GTPv2C DeleteBearerReq
......................................................................
s2b: Implement GTPv2C DeleteBearerReq
Sessions are now stored/kept upon CreateSession time until deleted
through DeleteBearerReq.
Related: OS#6046
Change-Id: I1e5af1ead17385d2e494f4c90ffe6455aee850da
---
M src/epdg_gtpc_s2b.erl
1 file changed, 137 insertions(+), 26 deletions(-)
Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/src/epdg_gtpc_s2b.erl b/src/epdg_gtpc_s2b.erl
index 82985a5..a5658f1 100644
--- a/src/epdg_gtpc_s2b.erl
+++ b/src/epdg_gtpc_s2b.erl
@@ -70,7 +70,9 @@
rport :: non_neg_integer(),
restart_counter :: 0..255,
seq_no :: 0..16#ffffffff,
- sess_list %% TODO: fill it, list of gtp_session
+ next_local_control_tei = 1 :: 0..16#ffffffff,
+ next_local_data_tei = 1 :: 0..16#ffffffff,
+ sessions = sets:new()
}).
-record(gtp_bearer, {
@@ -134,36 +136,45 @@
gen_server:call(?SERVER,
{gtpc_create_session_req, {Imsi}}).
-handle_call({gtpc_create_session_req, {Imsi}}, _From, State) ->
- Sess = new_gtp_session(Imsi, State),
- Req = gen_create_session_request(Sess, State),
+handle_call({gtpc_create_session_req, {Imsi}}, _From, State0) ->
+ {Sess0, State1} = find_or_new_gtp_session(Imsi, State0),
+ Req = gen_create_session_request(Sess0, State1),
%TODO: increment State.seq_no.
- tx_gtp(Req, State),
+ tx_gtp(Req, State1),
lager:debug("Waiting for CreateSessionResponse~n", []),
receive
{udp, _Socket, IP, InPortNo, RxMsg} ->
try
Resp = gtp_packet:decode(RxMsg),
- logger:info("s2b: Rx from IP ~p port ~n ~p~n", [IP, InPortNo,
Resp]),
- %% TODO: store Sess in State.
- {reply, {ok, Resp}, State}
+ lager:info("s2b: Rx from IP ~p port ~p ~p~n", [IP, InPortNo,
Resp]),
+ Sess1 = update_gtp_session_from_create_session_response(Resp, Sess0),
+ lager:info("s2b: Updated Session after create_session_response:
~p~n", [Sess1]),
+ State2 = update_gtp_session(Sess0, Sess1, State1),
+ {reply, {ok, Resp}, State2}
catch Any ->
- logger:error("Error sending message to receiver, ERROR: ~p~n",
[Any]),
- {reply, {error, decode_failure}, State}
+ lager:error("Error sending message to receiver, ERROR: ~p~n",
[Any]),
+ {reply, {error, decode_failure}, State1}
end
after 5000 ->
- logger:error("Timeout waiting for CreateSessionResponse for ~p~n",
[Req]),
- {reply, timeout, State}
+ lager:error("Timeout waiting for CreateSessionResponse for ~p~n",
[Req]),
+ {reply, timeout, State1}
end.
%% @callback gen_server
handle_cast(stop, State) ->
{stop, normal, State};
-handle_cast(_Req, State) ->
+handle_cast(Req, State) ->
+ lager:info("S2b handle_cast: ~p ~n", [Req]),
{noreply, State}.
%% @callback gen_server
-handle_info(_Info, State) ->
+handle_info({udp, _Socket, IP, InPortNo, RxMsg}, State) ->
+ lager:info("S2b: Rx from IP ~p port ~p: ~p~n", [IP, InPortNo, RxMsg]),
+ Req = gtp_packet:decode(RxMsg),
+ lager:info("S2b: Rx from IP ~p port ~p: ~p~n", [IP, InPortNo, Req]),
+ rx_gtp(Req, State);
+handle_info(Info, State) ->
+ lager:info("S2b handle_info: ~p ~n", [Info]),
{noreply, State}.
%% @callback gen_server
@@ -185,6 +196,76 @@
%% Internal Function Definitions
%% ------------------------------------------------------------------
+new_gtp_session(Imsi, State) ->
+ % TODO: find non-used local TEI inside State
+ Bearer = #gtp_bearer{
+ ebi = 5,
+ local_data_tei = State#gtp_state.next_local_data_tei
+ },
+ Sess = #gtp_session{imsi = Imsi,
+ apn = ?APN,
+ local_control_tei = State#gtp_state.next_local_control_tei,
+ bearer = Bearer
+ },
+ NewSt = State#gtp_state{next_local_control_tei =
State#gtp_state.next_local_control_tei + 1,
+ next_local_data_tei = State#gtp_state.next_local_data_tei +
1,
+ sessions = sets:add_element(Sess,
State#gtp_state.sessions)},
+ {Sess, NewSt}.
+
+% returns Sess if found, undefined it not
+find_gtp_session_by_imsi(Imsi, State) ->
+ sets:fold(
+ fun(SessIt = #gtp_session{imsi = Imsi}, _AccIn) -> SessIt;
+ (_, AccIn) -> AccIn
+ end,
+ undefined,
+ State#gtp_state.sessions).
+
+find_or_new_gtp_session(Imsi, State) ->
+ Sess = find_gtp_session_by_imsi(Imsi, State),
+ case Sess of
+ #gtp_session{imsi = Imsi} ->
+ {Sess, State};
+ undefined ->
+ new_gtp_session(Imsi, State)
+ end.
+
+update_gtp_session(OldSess, NewSess, State) ->
+ SetRemoved = sets:del_element(OldSess, State#gtp_state.sessions),
+ SetUpdated = sets:add_element(NewSess, SetRemoved),
+ State#gtp_state{sessions = SetUpdated}.
+
+delete_gtp_session(Sess, State) ->
+ SetRemoved = sets:del_element(Sess, State#gtp_state.sessions),
+ State#gtp_state{sessions = SetRemoved}.
+
+update_gtp_session_from_create_session_response_ie(none, Sess) ->
+ Sess;
+update_gtp_session_from_create_session_response_ie({_,
+
#v2_fully_qualified_tunnel_endpoint_identifier{
+ interface_type = _Interface,
+ key = TEI, ipv4 = _IP4, ipv6 =
_IP6},
+ Next}, Sess) ->
+ update_gtp_session_from_create_session_response_ie(maps:next(Next),
Sess#gtp_session{remote_control_tei = TEI});
+update_gtp_session_from_create_session_response_ie({_, _, Next},
+ Sess) ->
+ update_gtp_session_from_create_session_response_ie(maps:next(Next), Sess).
+
+update_gtp_session_from_create_session_response_ies(#gtp{ie = IEs}, Sess) ->
+ update_gtp_session_from_create_session_response_ie(maps:next(maps:iterator(IEs)),
Sess).
+
+update_gtp_session_from_create_session_response(Resp = #gtp{version = v2, type =
create_session_response}, Sess) ->
+ update_gtp_session_from_create_session_response_ies(#gtp{ie = Resp#gtp.ie}, Sess).
+
+% returns Sess if found, undefined it not
+find_gtp_session_by_local_teic(LocalControlTei, State) ->
+ sets:fold(
+ fun(SessIt = #gtp_session{local_control_tei = LocalControlTei}, _AccIn) ->
SessIt;
+ (_, AccIn) -> AccIn
+ end,
+ undefined,
+ State#gtp_state.sessions).
+
%% connect/2
connect(Name, {Socket, RemoteAddr, RemotePort}) ->
lager:info("~s connecting to IP ~s port ~p~n", [Name, RemoteAddr,
RemotePort]),
@@ -193,23 +274,27 @@
connect(Address) ->
connect(?SVC_NAME, Address).
+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
+ undefined ->
+ lager:error("Rx unknown TEI ~p: ~p~n", [Req#gtp.tei, Req]),
+ {noreply, State};
+ Sess ->
+ Resp = gen_delete_bearer_response(Req, Sess, request_accepted, State),
+ tx_gtp(Resp, State),
+ State1 = delete_gtp_session(Sess, State),
+ {noreply, State1}
+ end;
+rx_gtp(Req, State) ->
+ lager:error("S2b: UNIMPLEMENTED Rx: ~p~n", [Req]),
+ {noreply, State}.
+
tx_gtp(Req, State) ->
lager:info("s2b: Tx ~p~n", [Req]),
Msg = gtp_packet:encode(Req),
gen_udp:send(State#gtp_state.socket, State#gtp_state.raddr, State#gtp_state.rport,
Msg).
-new_gtp_session(Imsi, _State) ->
- % TODO: find non-used local TEI inside State
- Bearer = #gtp_bearer{
- ebi = 5,
- local_data_tei = 1
- },
- #gtp_session{imsi = Imsi,
- apn = ?APN,
- local_control_tei = 0,
- bearer = Bearer
- }.
-
%% 7.2.1 Create Session Request
gen_create_session_request(#gtp_session{imsi = Imsi,
apn = Apn,
@@ -249,4 +334,17 @@
],
#gtp{version = v2, type = create_session_request, tei = 0, 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,
+ #gtp_state{restart_counter = RCnt}) ->
+ IEs = [#v2_recovery{restart_counter = RCnt},
+ #v2_cause{v2_cause = GtpCause}
+ ],
+ #gtp{version = v2,
+ type = delete_bearer_response,
+ tei = RemoteCtlTEI,
+ seq_no = Req#gtp.seq_no,
+ ie = IEs}.
+
--
To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/34896?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: I1e5af1ead17385d2e494f4c90ffe6455aee850da
Gerrit-Change-Number: 34896
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged