blob: aee72c62a75adb5c8cc7b831ebf10dfa78297aaf [file] [log] [blame]
Harald Welte033cef02010-12-19 22:47:14 +01001% ITU-T Q.71x SCCP Message coding / decoding
2
3% (C) 2010 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/>.
19
20-module(sccp_codec).
21-author('Harald Welte <laforge@gnumonks.org>').
22-include("sccp.hrl").
23
24-export([parse_sccp_msg/1, encode_sccp_msg/1, encode_sccp_msgt/2]).
25
26-compile(export_all).
27
Harald Welte2b4b2672011-02-03 12:50:41 +010028parse_point_code(BinPC, PCind) when is_binary(BinPC) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010029 case PCind of
30 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010031 <<PointCode:16/big, Remain/binary>> = BinPC;
Harald Welteba6fdbb2011-01-23 22:04:39 +010032 _ ->
33 Remain = BinPC,
Harald Welte2b4b2672011-02-03 12:50:41 +010034 PointCode = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010035 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010036 {Remain, PointCode}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010037
Harald Welte2b4b2672011-02-03 12:50:41 +010038parse_ssn(BinSSN, SSNind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010039 case SSNind of
40 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010041 <<SSN:8, Remain/binary>> = BinSSN;
Harald Welteba6fdbb2011-01-23 22:04:39 +010042 _ ->
43 Remain = BinSSN,
Harald Welte2b4b2672011-02-03 12:50:41 +010044 SSN = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010045 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010046 {Remain, SSN}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010047
48enc_is_odd(Enc) ->
49 case Enc of
50 1 -> 1;
51 _ -> 0
52 end.
53
Harald Welte2b4b2672011-02-03 12:50:41 +010054parse_gt(BinGT, GTind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010055 case GTind of
56 ?SCCP_GTI_NO_GT ->
Harald Welte2b4b2672011-02-03 12:50:41 +010057 undef;
Harald Welteba6fdbb2011-01-23 22:04:39 +010058 ?SCCP_GTI_NAT_ONLY ->
59 % Figure 7/Q.713
60 <<Odd:1, Nature:7, Digits/binary>> = BinGT,
61 PhoneNum = isup_codec:parse_isup_party(Digits, Odd),
Harald Welte2b4b2672011-02-03 12:50:41 +010062 #global_title{gti = GTind,
63 nature_of_addr_ind = Nature,
64 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010065 ?SCCP_GTI_TT_ONLY ->
66 % Figure 9/Q.913
67 <<TransType:8, Digits/binary>> = BinGT,
68 % Used in national interfaces only, we cannot parse Digits
Harald Welte2b4b2672011-02-03 12:50:41 +010069 #global_title{gti = GTind,
70 trans_type = TransType,
71 phone_number = Digits};
Harald Welteba6fdbb2011-01-23 22:04:39 +010072 ?SCCP_GTI_TT_NP_ENC ->
73 % Figure 10/Q.713
74 <<TransType:8, NumPlan:4, Enc:4, Digits/binary>> = BinGT,
75 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010076 #global_title{gti = GTind,
77 trans_type = TransType, encoding = Enc,
78 numbering_plan = NumPlan,
79 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010080 ?SCCP_GTI_TT_NP_ENC_NAT ->
81 % Figure 11/Q.713
82 <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, Digits/binary>> = BinGT,
83 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010084 #global_title{gti = GTind,
85 trans_type = TransType, encoding = Enc,
86 numbering_plan = NumPlan,
87 nature_of_addr_ind = Nature,
88 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010089 _ ->
Harald Welte2b4b2672011-02-03 12:50:41 +010090 BinGT
91 end.
Harald Welteba6fdbb2011-01-23 22:04:39 +010092
93% parse SCCP Address
94parse_sccp_addr(BinAddr) when is_binary(BinAddr) ->
95 <<ResNatUse:1, RoutInd:1, GTind:4, SSNind:1, PCind:1, Remain/binary>> = BinAddr,
Harald Welte2b4b2672011-02-03 12:50:41 +010096 {RemainPC, OptPC} = parse_point_code(Remain, PCind),
97 {RemainSSN, OptSSN} = parse_ssn(RemainPC, SSNind),
98 OptGT = parse_gt(RemainSSN, GTind),
99 #sccp_addr{res_nat_use = ResNatUse, route_on_ssn = RoutInd,
100 point_code = OptPC, ssn = OptSSN, global_title = OptGT}.
Harald Welte033cef02010-12-19 22:47:14 +0100101
102% parse SCCP Optional Part
103parse_sccp_opt(OptType, OptLen, Content) ->
104 {OptType, {OptLen, Content}}.
105
106parse_sccp_opts(<<>>, OptList) ->
107 % empty list
108 OptList;
109parse_sccp_opts(<<0>>, OptList) ->
110 % end of options
111 OptList;
112parse_sccp_opts(OptBin, OptList) ->
113 <<OptType, OptLen, Content:OptLen/binary, Remain/binary>> = OptBin,
114 NewOpt = parse_sccp_opt(OptType, OptLen, Content),
115 parse_sccp_opts(Remain, [NewOpt|OptList]).
116
117% Parse incoming SCCP message, one function for every message type
118parse_sccp_msgt(?SCCP_MSGT_CR, DataBin) ->
119 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100120 <<_:8, SrcLocalRef:24/big, ProtoClass:8, RemainVar/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100121 % variable length fixed part
122 <<PtrVar:8, PtrOpt:8, _/binary>> = RemainVar,
123 CalledPartyLen = binary:at(RemainVar, PtrVar),
124 CalledParty = binary:part(RemainVar, PtrVar+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100125 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100126 % optional part
127 OptBin = binary:part(RemainVar, 1 + PtrOpt, byte_size(RemainVar)-(1+PtrOpt)),
128 OptList = parse_sccp_opts(OptBin, []),
129 %OptList = [],
130 % build parsed list of message
Harald Welte234c9562011-02-03 13:51:12 +0100131 [{src_local_ref, SrcLocalRef},{protocol_class, ProtoClass},{called_party_addr, CalledPartyDec}|OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100132parse_sccp_msgt(?SCCP_MSGT_CC, DataBin) ->
133 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100134 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ProtoClass:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100135 % optional part
136 OptList = parse_sccp_opts(Remain, []),
137 % build parsed list of message
138 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{protocol_class, ProtoClass}|OptList];
139parse_sccp_msgt(?SCCP_MSGT_CREF, DataBin) ->
140 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100141 <<_:8, DstLocalRef:24/big, RefusalCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100142 % optional part
143 OptList = parse_sccp_opts(Remain, []),
144 % build parsed list of message
145 [{dst_local_ref, DstLocalRef},{refusal_cause, RefusalCause}|OptList];
146parse_sccp_msgt(?SCCP_MSGT_RLSD, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100147 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100148 % optional part
149 OptList = parse_sccp_opts(Remain, []),
150 % build parsed list of message
151 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{release_cause, ReleaseCause}|OptList];
152parse_sccp_msgt(?SCCP_MSGT_RLC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100153 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100154 % build parsed list of message
155 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
156parse_sccp_msgt(?SCCP_MSGT_DT1, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100157 <<_:8, DstLocalRef:24/big, SegmReass:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100158 DataLen = binary:at(Remain, DataPtr-1),
159 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
160 % build parsed list of message
161 [{dst_local_ref, DstLocalRef},{segm_reass, SegmReass},{user_data, UserData}];
162parse_sccp_msgt(?SCCP_MSGT_DT2, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100163 <<_:8, DstLocalRef:24/big, SeqSegm:16, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100164 DataLen = binary:at(Remain, DataPtr-1),
165 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
166 % build parsed list of message
167 [{dst_local_ref, DstLocalRef},{seq_segm, SeqSegm},{user_data, UserData}];
168parse_sccp_msgt(?SCCP_MSGT_AK, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100169 <<_:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100170 [{dst_local_ref, DstLocalRef},{rx_seq_nr, RxSeqnr},{credit, Credit}];
171parse_sccp_msgt(?SCCP_MSGT_UDT, DataBin) ->
172 <<_:8, ProtoClass:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
173 % variable part
174 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
175 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100176 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100177 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
178 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100179 CallingPartyDec = parse_sccp_addr(CallingParty),
Harald Welte033cef02010-12-19 22:47:14 +0100180 DataLen = binary:at(Remain, DataPtr-1),
181 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
Harald Welte234c9562011-02-03 13:51:12 +0100182 [{protocol_class, ProtoClass},{called_party_addr, CalledPartyDec},
183 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100184parse_sccp_msgt(?SCCP_MSGT_UDTS, DataBin) ->
Harald Welte030f1092011-03-11 19:08:07 +0100185 <<_:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
186 % variable part
187 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
188 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
189 CalledPartyDec = parse_sccp_addr(CalledParty),
190 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
191 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
192 CallingPartyDec = parse_sccp_addr(CallingParty),
193 DataLen = binary:at(Remain, DataPtr-1),
194 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
195 [{return_cause, ReturnCause},{called_party_addr, CalledPartyDec},
196 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100197parse_sccp_msgt(?SCCP_MSGT_ED, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100198 <<_:8, DstLocalRef:24/big, DataPtr:8, Remain/binary>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100199 DataLen = binary:at(Remain, DataPtr-1),
200 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
201 [{dst_local_ref, DstLocalRef}, {user_data, UserData}];
202parse_sccp_msgt(?SCCP_MSGT_EA, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100203 <<_:8, DstLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100204 [{dst_local_ref, DstLocalRef}];
205parse_sccp_msgt(?SCCP_MSGT_RSR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100206 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100207 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{reset_cause, ResetCause}];
208parse_sccp_msgt(?SCCP_MSGT_RSC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100209 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100210 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
211parse_sccp_msgt(?SCCP_MSGT_ERR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100212 <<_:8, DstLocalRef:24/big, ErrCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100213 [{dst_local_ref, DstLocalRef},{error_cause, ErrCause}];
214parse_sccp_msgt(?SCCP_MSGT_IT, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100215 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ProtoClass:8, SegmSeq:16, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100216 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
217 {protocol_class, ProtoClass},{seq_segm, SegmSeq},{credit, Credit}].
218% FIXME: XUDT/XUDTS, LUDT/LUDTS
219
220% process one incoming SCCP message
221parse_sccp_msg(DataBin) ->
222 MsgType = binary:first(DataBin),
223 Parsed = parse_sccp_msgt(MsgType, DataBin),
224 {ok, #sccp_msg{msg_type = MsgType, parameters = Parsed}}.
225
226% Encoding Part
227
Harald Welte0e1709c2011-02-06 22:17:53 +0100228gt_enc_by_odd(Odd) ->
229 if Odd == 1 ->
230 1;
231 true ->
232 2
233 end.
234
Harald Welte234c9562011-02-03 13:51:12 +0100235encode_gt(#global_title{gti = GTind, phone_number = PhoneNum,
236 nature_of_addr_ind = Nature,
Harald Welte0e1709c2011-02-06 22:17:53 +0100237 trans_type = TransType, encoding = _EncOrig,
Harald Welte234c9562011-02-03 13:51:12 +0100238 numbering_plan = NumPlan}) ->
239 case GTind of
240 ?SCCP_GTI_NO_GT ->
241 {GTind, <<>>};
242 ?SCCP_GTI_NAT_ONLY ->
243 % Figure 7/Q.713
244 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
245 {GTind, <<OddEven:1, Nature:7, PhoneBin/binary>>};
246 ?SCCP_GTI_TT_ONLY ->
247 % Figure 9/Q.913
248 % Used in national interfaces only, we cannot parse Digits
249 {GTind, <<TransType:8, PhoneNum/binary>>};
250 ?SCCP_GTI_TT_NP_ENC ->
251 % Figure 10/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100252 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
253 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100254 {GTind, <<TransType:8, NumPlan:4, Enc:4, PhoneBin/binary>>};
255 ?SCCP_GTI_TT_NP_ENC_NAT ->
256 % Figure 11/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100257 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
258 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100259 {GTind, <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, PhoneBin/binary>>}
260 end.
261
262encode_pc(PointCode) ->
263 case PointCode of
264 undef ->
265 {0, <<>>};
266 _ ->
267 {1, <<PointCode:16/big>>}
268 end.
269
270encode_ssn(SSN) ->
271 case SSN of
272 undef ->
273 {0, <<>>};
274 _ ->
275 {1, <<SSN:8>>}
276 end.
277
278encode_sccp_addr(#sccp_addr{res_nat_use = ResNatUse,
279 route_on_ssn = RoutInd,
280 point_code = PointCode,
281 ssn = SSN,
282 global_title = GT}) ->
283
284 {GTind, GTbin} = encode_gt(GT),
285 {SSNind, SSNbin} = encode_ssn(SSN),
286 {PCind, PCbin} = encode_pc(PointCode),
287 <<ResNatUse:1, RoutInd:1, GTind:4, SSNind:1, PCind:1, PCbin/binary, SSNbin/binary, GTbin/binary>>.
288
289
Harald Welte033cef02010-12-19 22:47:14 +0100290encode_sccp_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
291 DataBinLen8 = DataBinLen*8,
292 <<OptNum:8, DataBinLen:8, DataBin:DataBinLen8>>;
293encode_sccp_opt({OptAtom,_}) when is_atom(OptAtom) ->
294 <<>>.
295
296encode_sccp_opts([], OptEnc) ->
297 % end of options + convert to binary
298 list_to_binary([OptEnc, ?SCCP_PNC_END_OF_OPTIONAL]);
299encode_sccp_opts([CurOpt|OptPropList], OptEnc) ->
300 CurOptEnc = encode_sccp_opt(CurOpt),
301 encode_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
302
303
304
305encode_sccp_msgt(?SCCP_MSGT_CR, Params) ->
306 SrcLocalRef = proplists:get_value(src_local_ref, Params),
307 ProtoClass = proplists:get_value(protocol_class, Params),
308 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100309 <<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, ProtoClass:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100310encode_sccp_msgt(?SCCP_MSGT_CC, Params) ->
311 SrcLocalRef = proplists:get_value(src_local_ref, Params),
312 DstLocalRef = proplists:get_value(dst_local_ref, Params),
313 ProtoClass = proplists:get_value(protocol_class, Params),
314 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100315 <<?SCCP_MSGT_CC:8, DstLocalRef:24/big, SrcLocalRef:24/big, ProtoClass:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100316encode_sccp_msgt(?SCCP_MSGT_CREF, Params) ->
317 DstLocalRef = proplists:get_value(dst_local_ref, Params),
318 RefusalCause = proplists:get_value(refusal_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100319 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100320 <<?SCCP_MSGT_CREF:8, DstLocalRef:24/big, RefusalCause:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100321encode_sccp_msgt(?SCCP_MSGT_RLSD, Params) ->
322 SrcLocalRef = proplists:get_value(src_local_ref, Params),
323 DstLocalRef = proplists:get_value(dst_local_ref, Params),
324 ReleaseCause = proplists:get_value(release_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100325 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100326 <<?SCCP_MSGT_RLSD:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, OptBin/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100327encode_sccp_msgt(?SCCP_MSGT_RLC, Params) ->
328 SrcLocalRef = proplists:get_value(src_local_ref, Params),
329 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100330 <<?SCCP_MSGT_RLC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100331encode_sccp_msgt(?SCCP_MSGT_DT1, Params) ->
332 DstLocalRef = proplists:get_value(dst_local_ref, Params),
333 SegmReass = proplists:get_value(segm_reass, Params),
334 UserData = proplists:get_value(user_data, Params),
335 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100336 <<?SCCP_MSGT_DT1:8, DstLocalRef:24/big, SegmReass:8, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100337encode_sccp_msgt(?SCCP_MSGT_DT2, Params) ->
338 DstLocalRef = proplists:get_value(dst_local_ref, Params),
339 SeqSegm = proplists:get_value(seq_segm, Params),
340 UserData = proplists:get_value(user_data, Params),
341 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100342 <<?SCCP_MSGT_DT2:8, DstLocalRef:24/big, SeqSegm:16, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100343encode_sccp_msgt(?SCCP_MSGT_AK, Params) ->
344 DstLocalRef = proplists:get_value(dst_local_ref, Params),
345 RxSeqnr = proplists:get_value(rx_seqnr, Params),
346 Credit = proplists:get_value(credit, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100347 <<?SCCP_MSGT_AK:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100348encode_sccp_msgt(?SCCP_MSGT_UDT, Params) ->
349 ProtoClass = proplists:get_value(protocol_class, Params),
350 CalledParty = proplists:get_value(called_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100351 CalledPartyEnc = encode_sccp_addr(CalledParty),
352 CalledPartyLen = byte_size(CalledPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100353 CallingParty = proplists:get_value(calling_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100354 CallingPartyEnc = encode_sccp_addr(CallingParty),
355 CallingPartyLen = byte_size(CallingPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100356 UserData = proplists:get_value(user_data, Params),
357 UserDataLen = byte_size(UserData),
358 % variable part
359 CalledPartyPtr = 3,
360 CallingPartyPtr = 2 + (1 + CalledPartyLen),
361 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100362 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
363 CallingPartyLen:8, CallingPartyEnc/binary,
Harald Weltec0696b02010-12-20 00:09:37 +0100364 UserDataLen:8, UserData/binary>>,
365 <<?SCCP_MSGT_UDT:8, ProtoClass:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Welte030f1092011-03-11 19:08:07 +0100366encode_sccp_msgt(?SCCP_MSGT_UDTS, Params) ->
367 ReturnCause = proplists:get_value(return_cause, Params),
368 CalledParty = proplists:get_value(called_party_addr, Params),
369 CalledPartyEnc = encode_sccp_addr(CalledParty),
370 CalledPartyLen = byte_size(CalledPartyEnc),
371 CallingParty = proplists:get_value(calling_party_addr, Params),
372 CallingPartyEnc = encode_sccp_addr(CallingParty),
373 CallingPartyLen = byte_size(CallingPartyEnc),
374 UserData = proplists:get_value(user_data, Params),
375 UserDataLen = byte_size(UserData),
376 % variable part
377 CalledPartyPtr = 3,
378 CallingPartyPtr = 2 + (1 + CalledPartyLen),
379 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
380 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
381 CallingPartyLen:8, CallingPartyEnc/binary,
382 UserDataLen:8, UserData/binary>>,
383 <<?SCCP_MSGT_UDTS:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100384encode_sccp_msgt(?SCCP_MSGT_ED, Params) ->
385 DstLocalRef = proplists:get_value(dst_local_ref, Params),
386 UserData = proplists:get_value(user_data, Params),
387 UserDataLen = byte_size(UserData),
388 DataPtr = 1,
Harald Welte56ee7a62010-12-20 13:34:32 +0100389 <<?SCCP_MSGT_ED:8, DstLocalRef:24/big, DataPtr:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100390encode_sccp_msgt(?SCCP_MSGT_EA, Params) ->
391 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100392 <<?SCCP_MSGT_EA:8, DstLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100393encode_sccp_msgt(?SCCP_MSGT_RSR, Params) ->
394 DstLocalRef = proplists:get_value(dst_local_ref, Params),
395 SrcLocalRef = proplists:get_value(src_local_ref, Params),
396 ResetCause = proplists:get_value(reset_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100397 <<?SCCP_MSGT_RSR:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100398encode_sccp_msgt(?SCCP_MSGT_RSC, Params) ->
399 DstLocalRef = proplists:get_value(dst_local_ref, Params),
400 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100401 <<?SCCP_MSGT_RSC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100402encode_sccp_msgt(?SCCP_MSGT_ERR, Params) ->
403 DstLocalRef = proplists:get_value(dst_local_ref, Params),
404 ErrCause = proplists:get_value(error_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100405 <<?SCCP_MSGT_ERR:8, DstLocalRef:24/big, ErrCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100406encode_sccp_msgt(?SCCP_MSGT_IT, Params) ->
407 DstLocalRef = proplists:get_value(dst_local_ref, Params),
408 SrcLocalRef = proplists:get_value(src_local_ref, Params),
409 ProtoClass = proplists:get_value(protocol_class, Params),
Harald Welte09b43992010-12-20 12:21:03 +0100410 SegmSeq = proplists:get_value(seq_segm, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100411 Credit = proplists:get_value(credit, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100412 <<?SCCP_MSGT_IT:8, DstLocalRef:24/big, SrcLocalRef:24/big, ProtoClass:8, SegmSeq:16, Credit:8>>.
Harald Weltec0696b02010-12-20 00:09:37 +0100413% FIXME: XUDT/XUDTS, LUDT/LUDTS
414
Harald Welte033cef02010-12-19 22:47:14 +0100415
416% encode one sccp message data structure into the on-wire format
417encode_sccp_msg(#sccp_msg{msg_type = MsgType, parameters = Params}) ->
418 encode_sccp_msgt(MsgType, Params).