blob: 69295ba133647abd34db1c2853d7a7542d5c5482 [file] [log] [blame]
Harald Welteee7964c2012-05-07 23:55:02 +02001% M2UA in accordance with RFC3331 (http://tools.ietf.org/html/rfc3331)
2
Harald Welte0d8af6b2013-07-27 15:02:17 +08003% (C) 2011-2013 by Harald Welte <laforge@gnumonks.org>
Harald Welteee7964c2012-05-07 23:55:02 +02004%
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/>.
19
20-module(sctp_m2ua).
21-author('Harald Welte <laforge@gnumonks.org>').
22-behaviour(sctp_core).
23
24-include_lib("kernel/include/inet_sctp.hrl").
25-include("osmo_util.hrl").
Harald Weltee58b38f2012-05-30 12:05:18 +020026-include("xua.hrl").
Harald Welteee7964c2012-05-07 23:55:02 +020027-include("m2ua.hrl").
Harald Weltecf74df52013-08-26 17:29:28 +020028-include("mtp3.hrl").
Harald Welteee7964c2012-05-07 23:55:02 +020029
Harald Welte0d8af6b2013-07-27 15:02:17 +080030-define(M2UA_STREAM_USER, 1).
31
Harald Welteee7964c2012-05-07 23:55:02 +020032-export([init/1, terminate/3, code_change/4, handle_event/3, handle_info/3]).
33
34-export([rx_sctp/4, mtp_xfer/2, state_change/3, prim_up/3]).
35
36-record(m2ua_state, {
37 asp_pid,
38 last_bsn_received,
Harald Weltecf74df52013-08-26 17:29:28 +020039 last_fsn_sent,
40 role
Harald Welteee7964c2012-05-07 23:55:02 +020041 }).
42
43%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44% gen_fsm callbacks
45%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46
Harald Welte0d8af6b2013-07-27 15:02:17 +080047init([Role]) ->
48 Fun = fun(Prim, Args) -> asp_prim_to_user(Prim, Args) end,
49 AsPid = undefined, % FIXME
50 % we use sua_asp module, as m2ua has no difference here
51 {ok, Asp} = gen_fsm:start_link(xua_asp_fsm, [AsPid, sua_asp, [], Fun, [self()], self(), Role], [{debug, [trace]}]),
Harald Weltecf74df52013-08-26 17:29:28 +020052 {ok, #m2ua_state{last_bsn_received=16#ffffff,
53 last_fsn_sent=16#ffffff, asp_pid=Asp, role=Role}}.
Harald Welteee7964c2012-05-07 23:55:02 +020054
55terminate(Reason, _State, _LoopDat) ->
56 io:format("Terminating ~p (Reason ~p)~n", [?MODULE, Reason]),
57 ok.
58
59code_change(_OldVsn, _State, LoopDat, _Extra) ->
60 {ok, LoopDat}.
61
62handle_event(_Event, State, LoopDat) ->
63 {next_state, State, LoopDat}.
64
65handle_info(_Info, State, LoopDat) ->
66 {next_state, State, LoopDat}.
67
68%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69% sctp_core callbacks
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71
72prim_up(#primitive{subsystem='M', gen_name = 'SCTP_ESTABLISH', spec_name = confirm}, State, LoopDat) ->
Harald Welte0d8af6b2013-07-27 15:02:17 +080073 % confirmation in case of active/connect mode
Harald Welteee7964c2012-05-07 23:55:02 +020074 Asp = LoopDat#m2ua_state.asp_pid,
75 gen_fsm:send_event(Asp, osmo_util:make_prim('M','ASP_UP',request)),
76 {ignore, LoopDat};
Harald Welte0d8af6b2013-07-27 15:02:17 +080077prim_up(#primitive{subsystem='M', gen_name = 'SCTP_ESTABLISH', spec_name = indication}, State, LoopDat) ->
78 % indication in case of passive/listen mode
Harald Welte0d8af6b2013-07-27 15:02:17 +080079 {ignore, LoopDat};
Harald Welteee7964c2012-05-07 23:55:02 +020080prim_up(#primitive{subsystem='M', gen_name = 'ASP_UP', spec_name = confirm}, State, LoopDat) ->
Harald Welte4540ecd2013-07-27 15:08:53 +080081 % confirmation in case of active/connect mode
Harald Welteee7964c2012-05-07 23:55:02 +020082 Asp = LoopDat#m2ua_state.asp_pid,
Harald Welte7ccc15e2013-08-27 10:27:52 +020083 % override mode, interface ID 1. FIXME: user-specify interface ID(s)
84 Pars = [{?M2UA_P_COM_TRAF_MODE_T, {4, 1}}, {?M2UA_P_COM_INTF_ID_INT, {4, 0}}],
85 gen_fsm:send_event(Asp, osmo_util:make_prim('M','ASP_ACTIVE',request,Pars)),
Harald Welteee7964c2012-05-07 23:55:02 +020086 {ignore, LoopDat};
Harald Welte287a3fd2013-08-27 12:14:07 +020087prim_up(#primitive{subsystem='M', gen_name = 'ASP_ACTIVE', spec_name = confirm}, State, LoopDat) ->
88 % FIXME: start a timer or have a separate FSM about it!
89 M = #xua_msg{version = 1, msg_class = ?M2UA_MSGC_MAUP,
90 msg_type = ?M2UA_MAUP_MSGT_EST_REQ,
91 payload = [{?M2UA_P_COM_INTF_ID_INT, {4, 0}}]},
92 LoopDat2 = mtp_xfer(M, LoopDat),
93 {ignore, LoopDat2};
94
95
Harald Welte4540ecd2013-07-27 15:08:53 +080096
Harald Welteee7964c2012-05-07 23:55:02 +020097prim_up(Prim, State, LoopDat) ->
Harald Weltecf74df52013-08-26 17:29:28 +020098 % default: forward all primitives to the user
Harald Welteee7964c2012-05-07 23:55:02 +020099 {ok, Prim, LoopDat}.
100
101
102% sctp_core indicates that we have received some data...
103rx_sctp(#sctp_sndrcvinfo{ppid = ?M2UA_PPID}, Data, State, LoopDat) ->
104 Asp = LoopDat#m2ua_state.asp_pid,
Harald Welte0d8af6b2013-07-27 15:02:17 +0800105 M2ua = xua_codec:parse_msg(Data),
Harald Welteee7964c2012-05-07 23:55:02 +0200106 % FIXME: check sequenc number linearity
107 case M2ua of
Harald Weltecf74df52013-08-26 17:29:28 +0200108 #xua_msg{msg_class = ?M2UA_MSGC_ASPSM} ->
Harald Welteee7964c2012-05-07 23:55:02 +0200109 gen_fsm:send_event(Asp, M2ua),
110 {ignore, LoopDat};
Harald Weltecf74df52013-08-26 17:29:28 +0200111 #xua_msg{msg_class = ?M2UA_MSGC_ASPTM} ->
Harald Welteee7964c2012-05-07 23:55:02 +0200112 gen_fsm:send_event(Asp, M2ua),
113 {ignore, LoopDat};
Harald Weltee58b38f2012-05-30 12:05:18 +0200114 #xua_msg{msg_class = ?M2UA_MSGC_MAUP,
Harald Weltee58b38f2012-05-30 12:05:18 +0200115 msg_type = ?M2UA_MAUP_MSGT_CONG_IND} ->
116 % FIXME
117 error_logger:error_report(["unimplemented message",
118 {msg_type, "CONG_IND"}]),
119 {ignore, LoopDat};
120 #xua_msg{msg_class = ?M2UA_MSGC_MAUP,
121 msg_type = ?M2UA_MAUP_MSGT_DATA_RETR_REQ} ->
122 % FIXME
123 error_logger:error_report(["unimplemented message",
124 {msg_type, "RETR_REQ"}]),
125 {ignore, LoopDat};
126 #xua_msg{msg_class = ?M2UA_MSGC_MAUP,
127 msg_type = ?M2UA_MAUP_MSGT_DATA} ->
Harald Welte287a3fd2013-08-27 12:14:07 +0200128 {_Len, M3bin} = proplists:get_value(?M2UA_P_M2UA_DATA1, M2ua#xua_msg.payload),
129 Mtp3 = mtp3_codec:parse_mtp3_msg(M3bin),
Harald Weltee58b38f2012-05-30 12:05:18 +0200130 Prim = osmo_util:make_prim('MTP','TRANSFER',indication, Mtp3),
Harald Welte0d8af6b2013-07-27 15:02:17 +0800131 {ok, Prim, LoopDat};
Harald Welteee7964c2012-05-07 23:55:02 +0200132 _ ->
Harald Weltecf74df52013-08-26 17:29:28 +0200133 rx_sctp(M2ua, State, LoopDat)
Harald Welteee7964c2012-05-07 23:55:02 +0200134 end.
135
Harald Weltecf74df52013-08-26 17:29:28 +0200136% SG side
137rx_sctp(#xua_msg{msg_class = ?M2UA_MSGC_MAUP,
138 msg_type = ?M2UA_MAUP_MSGT_EST_REQ}, State,
139 LoopDat = #m2ua_state{role=sg}) ->
140 % FIXME: respond with M2UA_MAUP_MSGT_EST_CONF
141 error_logger:error_report(["unimplemented message",
142 {msg_type, "EST_REQ"}]),
143 {ignore, LoopDat};
144rx_sctp(#xua_msg{msg_class = ?M2UA_MSGC_MAUP,
145 msg_type = ?M2UA_MAUP_MSGT_REL_REQ}, State,
146 LoopDat = #m2ua_state{role=sg}) ->
147 % FIXME: respond with M2UA_MAUP_MSGT_REL_CONF
148 error_logger:error_report(["unimplemented message",
149 {msg_type, "REL_REQ"}]),
150 {ignore, LoopDat};
151
152rx_sctp(M2ua = #xua_msg{msg_class = ?M2UA_MSGC_MAUP,
153 msg_type = ?M2UA_MAUP_MSGT_STATE_REQ}, State,
154 LoopDat = #m2ua_state{role=sg}) ->
155 handle_m2ua_state_req(M2ua),
156 {ignore, LoopDat};
157
158% ASP side
159rx_sctp(#xua_msg{msg_class = ?M2UA_MSGC_MAUP,
160 msg_type = ?M2UA_MAUP_MSGT_REL_CONF}, State,
161 LoopDat = #m2ua_state{role=asp}) ->
162 error_logger:error_report(["unimplemented message",
163 {msg_type, "REL_CONF"}]),
164 {ignore, LoopDat};
165
166rx_sctp(#xua_msg{msg_class = ?M2UA_MSGC_MAUP,
167 msg_type = ?M2UA_MAUP_MSGT_EST_CONF}, State,
168 LoopDat = #m2ua_state{role=asp}) ->
169 error_logger:error_report(["unimplemented message",
170 {msg_type, "EST_CONF"}]),
171 {ignore, LoopDat};
172
173rx_sctp(M2ua = #xua_msg{}, State, LoopDat) ->
174 % do something with link rel msgs
175 io:format("M2UA Unknown message ~p in state ~p~n", [M2ua, State]),
176 {ignore, LoopDat}.
177
178
Harald Welteee7964c2012-05-07 23:55:02 +0200179% MTP-TRANSFER.req has arrived at sctp_core, encapsulate+tx it
Harald Welte0d8af6b2013-07-27 15:02:17 +0800180mtp_xfer(M2ua, LoopDat) when is_record(M2ua, xua_msg) ->
181 M2uaBin = xua_codec:encode_msg(M2ua),
182 tx_sctp(?M2UA_STREAM_USER, M2uaBin),
183 LoopDat;
184
Harald Weltecf74df52013-08-26 17:29:28 +0200185mtp_xfer(Mtp3, LoopDat) when is_record(Mtp3, mtp3_msg) ->
186 MsgBin = mtp3_codec:encode_mtp3_msg(Mtp3),
187 mtp_xfer(MsgBin, LoopDat);
188
189mtp_xfer(Mtp3bin, LoopDat) when is_binary(Mtp3bin) ->
190 M2ua = #xua_msg{version = 1,
191 msg_class = ?M2UA_MSGC_MAUP,
Harald Weltee58b38f2012-05-30 12:05:18 +0200192 msg_type = ?M2UA_MAUP_MSGT_DATA,
Harald Weltecf74df52013-08-26 17:29:28 +0200193 payload = [{?M2UA_P_COM_INTF_ID_INT, {4, 0}},
194 {?M2UA_P_M2UA_DATA1, {byte_size(Mtp3bin), Mtp3bin}}]},
Harald Welte0d8af6b2013-07-27 15:02:17 +0800195 mtp_xfer(M2ua, LoopDat).
Harald Welteee7964c2012-05-07 23:55:02 +0200196
197state_change(_, established, LoopDat) ->
198 % emulate a 'start' from LSC
199 %gen_fsm:send_event(LoopDat#m2pa_state.lsc_pid, start),
200 LoopDat;
201state_change(established, _, LoopDat) ->
202 %gen_fsm:send_event(LoopDat#m2pa_state.lsc_pid, link_failure),
203 LoopDat;
204state_change(_, _, LoopDat) ->
205 LoopDat.
206
Harald Weltee58b38f2012-05-30 12:05:18 +0200207handle_m2ua_state_req(M2ua = #xua_msg{payload = Payload}) ->
208 {?M2UA_P_MAUP_STATE, State} = lists:keyfind(?M2UA_P_MAUP_STATE, 1, Payload),
209 % FIXME handle_m2ua_state_req(State).
210 % LOP_SET/CLEAR, EMER_SET/CLEAR, FLUSH_BUFFERSm CONTINUE, CLEAR_RTB, AUDIT, CONG*
211 % FIXME: respond with M2UA_MAUP_MSGT_STATE_CONF
212 error_logger:error_report(["unimplemented message",
213 {msg_type, "STATE_REQ"}]),
214 true.
Harald Welteee7964c2012-05-07 23:55:02 +0200215
216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217% helper functions
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219
220tx_sctp(Stream, Payload) when is_integer(Stream), is_binary(Payload) ->
221 Param = {Stream, ?M2UA_PPID, Payload},
222 % sent to 'ourselves' (behaviour master module)
223 gen_fsm:send_event(self(), osmo_util:make_prim('SCTP','TRANSFER',request,Param)).
Harald Welte0d8af6b2013-07-27 15:02:17 +0800224
225% callback fun for ASP FMS
226asp_prim_to_user(Prim, [SctpPid]) ->
227 gen_fsm:send_event(SctpPid, Prim).