blob: 2e586d17c3a9f0adce873c15847429f59f8d6019 [file] [log] [blame]
Harald Welte475ccdb2012-01-17 10:11:58 +01001% SCCP M3UA / SUA ASP gsn_fsm according to RFC3868 4.3.1
2
3% (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
4%
5% All Rights Reserved
6%
7% This program is free software; you can redistribute it and/or modify
8% it under the terms of the GNU Affero General Public License as
9% published by the Free Software Foundation; either version 3 of the
10% License, or (at your option) any later version.
11%
12% This program is distributed in the hope that it will be useful,
13% but WITHOUT ANY WARRANTY; without even the implied warranty of
14% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15% GNU General Public License for more details.
16%
17% You should have received a copy of the GNU Affero General Public License
18% along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Weltef8bf0322012-04-16 13:10:47 +020019%
20% Additional Permission under GNU AGPL version 3 section 7:
21%
22% If you modify this Program, or any covered work, by linking or
23% combining it with runtime libraries of Erlang/OTP as released by
24% Ericsson on http://www.erlang.org (or a modified version of these
25% libraries), containing parts covered by the terms of the Erlang Public
26% License (http://www.erlang.org/EPLICENSE), the licensors of this
27% Program grant you additional permission to convey the resulting work
28% without the need to license the runtime libraries of Erlang/OTP under
29% the GNU Affero General Public License. Corresponding Source for a
30% non-source form of such a combination shall include the source code
31% for the parts of the runtime libraries of Erlang/OTP used as well as
32% that of the covered work.
Harald Welte475ccdb2012-01-17 10:11:58 +010033
34-module(xua_asp_fsm).
35-author('Harald Welte <laforge@gnumonks.org>').
36-behaviour(gen_fsm).
37
38-include("osmo_util.hrl").
39-include("m3ua.hrl").
40
41% gen_fsm exports
Harald Welte312a1eb2012-05-09 00:02:59 +020042-export([init/1, terminate/3, code_change/4, handle_event/3, handle_info/3,
43 handle_sync_event/4]).
Harald Welte475ccdb2012-01-17 10:11:58 +010044
45% states in this FSM
46-export([asp_down/2, asp_inactive/2, asp_active/2]).
47
48% helper functions exporte to callback modules
49-export([send_sctp_to_peer/2, send_prim_to_user/2]).
50
Harald Welte312a1eb2012-05-09 00:02:59 +020051% global exports
Harald Welte0d8af6b2013-07-27 15:02:17 +080052-export([get_state/1, start_link/7]).
Harald Welte312a1eb2012-05-09 00:02:59 +020053
Harald Welte475ccdb2012-01-17 10:11:58 +010054-export([behaviour_info/1]).
55
56behaviour_info(callbacks) ->
57 [{gen_xua_msg, 3}, {asp_down, 3}, {asp_inactive, 3}, {asp_active, 3}].
58
59% Timeouts in milliseconds
60-define(T_ACK_TIMEOUT, 2*60*100).
61
62-record(asp_state, {
63 module,
Harald Welte0d8af6b2013-07-27 15:02:17 +080064 role, % asp, sg
Harald Welte475ccdb2012-01-17 10:11:58 +010065 t_ack,
66 ext_state,
67 user_fun,
68 user_args,
Harald Welteeb618852012-05-08 23:50:04 +020069 as_pid,
Harald Welte475ccdb2012-01-17 10:11:58 +010070 sctp_pid
71 }).
72
Harald Welte0d8af6b2013-07-27 15:02:17 +080073start_link(AsPid, Module, ModuleArgs, UserFun, UserArgs, SctpPid, Role) ->
74 gen_fsm:start_link(?MODULE, [AsPid, Module, ModuleArgs, UserFun, UserArgs, SctpPid, Role], [{debug, [trace]}]).
Harald Weltedd35d2c2012-05-09 00:10:39 +020075
Harald Welte475ccdb2012-01-17 10:11:58 +010076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77% gen_fsm callbacks
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79
Harald Welte0d8af6b2013-07-27 15:02:17 +080080init([AsPid, Module, ModuleArgs, UserFun, UserArgs, SctpPid, Role]) ->
Harald Welte475ccdb2012-01-17 10:11:58 +010081 {ok, ExtState} = Module:init(ModuleArgs),
82 AspState = #asp_state{module = Module,
83 user_fun = UserFun,
84 user_args = UserArgs,
85 ext_state = ExtState,
Harald Welteeb618852012-05-08 23:50:04 +020086 as_pid = AsPid,
Harald Welte475ccdb2012-01-17 10:11:58 +010087 sctp_pid = SctpPid,
Harald Welte0d8af6b2013-07-27 15:02:17 +080088 role = Role},
Harald Welte475ccdb2012-01-17 10:11:58 +010089 {ok, asp_down, AspState}.
90
91terminate(Reason, State, _LoopDat) ->
92 io:format("Terminating ~p in State ~p (Reason: ~p)~n",
93 [?MODULE, State, Reason]),
94 ok.
95
96code_change(_OldVsn, StateName, LoopDat, _Extra) ->
97 {ok, StateName, LoopDat}.
98
99handle_event(Event, State, LoopDat) ->
100 io:format("Unknown Event ~p in state ~p~n", [Event, State]),
101 {next_state, State, LoopDat}.
102
103
104handle_info(Info, State, LoopDat) ->
105 io:format("Unknown Info ~p in state ~p~n", [Info, State]),
106 {next_state, State, LoopDat}.
107
Harald Welte312a1eb2012-05-09 00:02:59 +0200108handle_sync_event(get_state, _From, StateName, LoopDat) ->
109 {reply, state2aspas(StateName), StateName, LoopDat}.
110
111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112% exports
113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114
115get_state(Pid) ->
116 gen_fsm:sync_send_all_state_event(Pid, get_state).
Harald Welte475ccdb2012-01-17 10:11:58 +0100117
118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119% STATE "asp_down"
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121
122asp_down(#primitive{subsystem = 'M', gen_name = 'ASP_UP',
Harald Welte0d8af6b2013-07-27 15:02:17 +0800123 spec_name = request, parameters = _Params},
124 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100125 % M-ASP_UP.req from user, generate message and send to remote peer
126 send_msg_start_tack(LoopDat, asp_down, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP, []);
127asp_down({timer_expired, t_ack, {?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP, Params}}, LoopDat) ->
128 send_msg_start_tack(LoopDat, asp_down, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP, Params);
129
Harald Welte0d8af6b2013-07-27 15:02:17 +0800130asp_down({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP_ACK},
131 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100132 timer:cancel(LoopDat#asp_state.t_ack),
133 % transition into ASP_INACTIVE
134 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_UP',confirm)),
Harald Welteeb618852012-05-08 23:50:04 +0200135 next_state(asp_inactive, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100136
Harald Welte0d8af6b2013-07-27 15:02:17 +0800137asp_down({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP},
138 LoopDat = #asp_state{role=sg}) ->
139 % transition into ASP_INACTIVE
Harald Weltea5409502013-07-27 15:08:29 +0800140 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_UP',indication)),
Harald Welte9b9ec4a2013-07-27 15:55:36 +0800141 send_msg(LoopDat, asp_inactive, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPUP_ACK, []);
Harald Welte0d8af6b2013-07-27 15:02:17 +0800142
Harald Welte475ccdb2012-01-17 10:11:58 +0100143asp_down(WhateverElse, LoopDat = #asp_state{module = Module, ext_state = ExtState}) ->
Harald Weltead6e5a92013-07-27 15:51:20 +0800144 {next_state, State, LDnew} = Module:asp_down(WhateverElse, ExtState, LoopDat),
Harald Welteeb618852012-05-08 23:50:04 +0200145 next_state(State, LDnew).
Harald Welte475ccdb2012-01-17 10:11:58 +0100146
147
148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149% STATE "asp_inactive"
150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151
152asp_inactive(#primitive{subsystem = 'M', gen_name = 'ASP_ACTIVE',
Harald Welte0d8af6b2013-07-27 15:02:17 +0800153 spec_name = request, parameters = Params},
154 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100155 % M-ASP_ACTIVE.req from user, generate message and send to remote peer
156 send_msg_start_tack(LoopDat, asp_inactive, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC,
157 Params);
158
159asp_inactive({timer_expired, t_ack, {?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC, Params}}, LoopDat) ->
160 send_msg_start_tack(LoopDat, asp_inactive, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC, Params);
161
162asp_inactive(#primitive{subsystem = 'M', gen_name = 'ASP_DOWN',
Harald Welte0d8af6b2013-07-27 15:02:17 +0800163 spec_name = request, parameters = _Params},
164 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100165 % M-ASP_DOWN.req from user, generate message and send to remote peer
166 send_msg_start_tack(LoopDat, asp_inactive, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, []);
167
168asp_inactive({timer_expired, t_ack, {?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, Params}}, LoopDat) ->
169 send_msg_start_tack(LoopDat, asp_inactive, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, Params);
170
Harald Welte0d8af6b2013-07-27 15:02:17 +0800171asp_inactive({xua_msg,?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC_ACK},
172 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100173 timer:cancel(LoopDat#asp_state.t_ack),
174 % transition into ASP_ACTIVE
175 % signal this to the user
176 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_ACTIVE',confirm)),
Harald Welteeb618852012-05-08 23:50:04 +0200177 next_state(asp_active, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100178
Harald Welte0d8af6b2013-07-27 15:02:17 +0800179asp_inactive({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN_ACK},
180 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100181 timer:cancel(LoopDat#asp_state.t_ack),
182 % transition into ASP_DOWN
183 % signal this to the user
184 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_DOWN',confirm)),
Harald Welteeb618852012-05-08 23:50:04 +0200185 next_state(asp_down, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100186
Harald Welte0d8af6b2013-07-27 15:02:17 +0800187
188asp_inactive({xua_msg,?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC},
189 LoopDat = #asp_state{role=sg}) ->
190 % transition into ASP_ACTIVE
191 % signal this to the user
192 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_ACTIVE',indication)),
193 send_msg(LoopDat, asp_active, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPAC_ACK, []);
194
195asp_inactive({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN},
196 LoopDat = #asp_state{role=asp}) ->
197 % transition into ASP_DOWN
198 % signal this to the user
199 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_DOWN',indication)),
200 send_msg(LoopDat, asp_active, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN_ACK, []);
201
Harald Welte475ccdb2012-01-17 10:11:58 +0100202asp_inactive(WhateverElse, LoopDat = #asp_state{module = Module, ext_state = ExtState}) ->
Harald Weltead6e5a92013-07-27 15:51:20 +0800203 {next_state, State, LDnew} = Module:asp_inactive(WhateverElse, ExtState, LoopDat),
Harald Welteeb618852012-05-08 23:50:04 +0200204 next_state(State, LDnew).
Harald Welte475ccdb2012-01-17 10:11:58 +0100205
206
207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208% STATE "asp_active"
209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210
Harald Welte0d8af6b2013-07-27 15:02:17 +0800211asp_active({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN_ACK},
212 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100213 timer:cancel(LoopDat#asp_state.t_ack),
214 % transition into ASP_DOWN
215 % signal this to the user
216 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_DOWN',confirm)),
Harald Welteeb618852012-05-08 23:50:04 +0200217 next_state(asp_down, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100218
Harald Welte0d8af6b2013-07-27 15:02:17 +0800219asp_active({xua_msg, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA_ACK},
220 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100221 timer:cancel(LoopDat#asp_state.t_ack),
222 % transition into ASP_INACTIVE
223 % signal this to the user
224 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_INACTIVE',confirm)),
Harald Welteeb618852012-05-08 23:50:04 +0200225 next_state(asp_inactive, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100226
227asp_active(#primitive{subsystem = 'M', gen_name = 'ASP_DOWN',
Harald Welte0d8af6b2013-07-27 15:02:17 +0800228 spec_name = request, parameters = _Params},
229 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100230 % M-ASP_DOWN.req from user, generate message and send to remote peer
231 send_msg_start_tack(LoopDat, asp_active, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, []);
232
233asp_active({timer_expired, t_ack, {?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, Params}}, LoopDat) ->
234 send_msg_start_tack(LoopDat, asp_active, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN, Params);
235
236asp_active(#primitive{subsystem = 'M', gen_name = 'ASP_INACTIVE',
Harald Welte0d8af6b2013-07-27 15:02:17 +0800237 spec_name = request, parameters = _Params},
238 LoopDat = #asp_state{role=asp}) ->
Harald Welte475ccdb2012-01-17 10:11:58 +0100239 % M-ASP_INACTIVE.req from user, generate message and send to remote peer
240 send_msg_start_tack(LoopDat, asp_active, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA, []);
241
242asp_active({timer_expired, t_ack, {?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA, Params}}, LoopDat) ->
243 send_msg_start_tack(LoopDat, asp_active, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA, Params);
244
Harald Welte0d8af6b2013-07-27 15:02:17 +0800245asp_active({xua_msg, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA},
246 LoopDat = #asp_state{role=sg}) ->
247 % transition into ASP_INACTIVE
248 % signal this to user
249 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_INACTIVE',indication)),
250 send_msg(LoopDat, asp_inactive, ?M3UA_MSGC_ASPTM, ?M3UA_MSGT_ASPTM_ASPIA_ACK, []);
251
252asp_active({xua_msg, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN},
253 LoopDat = #asp_state{role=sg}) ->
254 % transition into ASP_INACTIVE
255 % signal this to user
256 send_prim_to_user(LoopDat, osmo_util:make_prim('M','ASP_DOWN',indication)),
257 send_msg(LoopDat, asp_down, ?M3UA_MSGC_ASPSM, ?M3UA_MSGT_ASPSM_ASPDN_ACK, []);
258
259
Harald Welte475ccdb2012-01-17 10:11:58 +0100260asp_active(#primitive{subsystem = 'MTP', gen_name = 'TRANSFER',
261 spec_name = request, parameters = Params}, LoopDat) ->
262 % MTP-TRANSFER.req from user app: Send message to remote peer
263 OptList = [{?M3UA_IEI_PROTOCOL_DATA, Params}],
264 Msg = #m3ua_msg{version = 1, msg_class = ?M3UA_MSGC_TRANSFER,
265 msg_type = ?M3UA_MSGT_XFR_DATA,
266 payload = OptList},
267 send_sctp_to_peer(LoopDat, Msg),
Harald Welteeb618852012-05-08 23:50:04 +0200268 next_state(asp_active, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100269asp_active(#m3ua_msg{version = 1, msg_class = ?M3UA_MSGC_TRANSFER,
270 msg_type = ?M3UA_MSGT_XFR_DATA, payload = Params}, LoopDat) ->
271 % Data transfer from remote entity: Send MTP-TRANSFER.ind primitive to the user
272 Mtp3 = proplists:get_value(?M3UA_IEI_PROTOCOL_DATA, Params),
273 send_prim_to_user(LoopDat, osmo_util:make_prim('MTP','TRANSFER',indication,Mtp3)),
Harald Welteeb618852012-05-08 23:50:04 +0200274 next_state(asp_active, LoopDat);
Harald Welte475ccdb2012-01-17 10:11:58 +0100275
276asp_active(WhateverElse, LoopDat = #asp_state{module = Module, ext_state = ExtState}) ->
Harald Weltead6e5a92013-07-27 15:51:20 +0800277 {next_state, State, LDnew} = Module:asp_active(WhateverElse, ExtState, LoopDat),
Harald Welteeb618852012-05-08 23:50:04 +0200278 next_state(State, LDnew).
Harald Welte475ccdb2012-01-17 10:11:58 +0100279
280
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282% helper functions
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284
285% helper to send one of the up/down/act/inact management messages + start timer
286send_msg_start_tack(LoopDat, State, MsgClass, MsgType, Params) ->
287 Module = LoopDat#asp_state.module,
288 % generate and send the respective message
289 %Msg = #m3ua_msg{version = 1, msg_class = MsgClass, msg_type = MsgType, payload = Params},
290 Msg = Module:gen_xua_msg(MsgClass, MsgType, Params),
291 send_sctp_to_peer(LoopDat, Msg),
292 % start T(ack) timer and wait for ASP_UP_ACK
293 timer:cancel(LoopDat#asp_state.t_ack),
294 {ok, Tack} = timer:apply_after(?T_ACK_TIMEOUT, gen_fsm, send_event,
295 [self(), {timer_expired, t_ack, {MsgClass, MsgType, Params}}]),
Harald Welteeb618852012-05-08 23:50:04 +0200296 next_state(State, LoopDat#asp_state{t_ack = Tack}).
Harald Welte475ccdb2012-01-17 10:11:58 +0100297
Harald Welte0d8af6b2013-07-27 15:02:17 +0800298send_msg(LoopDat, State, MsgClass, MsgType, Params) ->
299 Module = LoopDat#asp_state.module,
300 % generate and send the respective message
301 Msg = Module:gen_xua_msg(MsgClass, MsgType, Params),
302 send_sctp_to_peer(LoopDat, Msg),
303 next_state(State, LoopDat).
Harald Welte475ccdb2012-01-17 10:11:58 +0100304
305send_prim_to_user(LoopDat, Prim) when is_record(LoopDat, asp_state),
306 is_record(Prim, primitive) ->
307 #asp_state{user_fun = Fun, user_args = Args} = LoopDat,
308 Fun(Prim, Args).
309
Harald Welteeb618852012-05-08 23:50:04 +0200310state2aspas(asp_down) -> 'ASP_DOWN';
311state2aspas(asp_inactive) -> 'ASP_INACTIVE';
312state2aspas(asp_active) -> 'ASP_ACTIVE'.
313
314% propagate an ASP state transition as ASPAS primitive to AS
315next_state(State, LoopDat = #asp_state{as_pid = AsPid}) ->
316 Prim = osmo_util:make_prim('ASPAS', state2aspas(State), indication),
Harald Welte43ceb092013-07-27 14:12:58 +0800317 case AsPid of
318 undefined ->
319 ok;
320 _ ->
321 gen_fsm:send_event(AsPid, Prim)
322 end,
Harald Welteeb618852012-05-08 23:50:04 +0200323 {next_state, State, LoopDat}.
Harald Welte475ccdb2012-01-17 10:11:58 +0100324
325% Helper function to send data to the SCTP peer
326send_sctp_to_peer(LoopDat, Msg) ->
327 Prim = osmo_util:make_prim('MTP','TRANSFER',request, Msg),
328 gen_fsm:send_event(LoopDat#asp_state.sctp_pid, Prim).