blob: a3b03526fffb3adead227e7cc61e785e2a3f70f5 [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 Welte2edaf552011-04-02 16:46:16 +020028-compile({parse_transform, exprecs}).
Harald Welte0f2f5962011-04-04 15:59:49 +020029-export_records([global_title, sccp_addr, sccp_msg]).
Harald Welte2edaf552011-04-02 16:46:16 +020030
Harald Welte2b4b2672011-02-03 12:50:41 +010031parse_point_code(BinPC, PCind) when is_binary(BinPC) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010032 case PCind of
33 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010034 <<PointCode:16/big, Remain/binary>> = BinPC;
Harald Welteba6fdbb2011-01-23 22:04:39 +010035 _ ->
36 Remain = BinPC,
Harald Welte2b4b2672011-02-03 12:50:41 +010037 PointCode = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010038 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010039 {Remain, PointCode}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010040
Harald Welte2b4b2672011-02-03 12:50:41 +010041parse_ssn(BinSSN, SSNind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010042 case SSNind of
43 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010044 <<SSN:8, Remain/binary>> = BinSSN;
Harald Welteba6fdbb2011-01-23 22:04:39 +010045 _ ->
46 Remain = BinSSN,
Harald Welte2b4b2672011-02-03 12:50:41 +010047 SSN = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010048 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010049 {Remain, SSN}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010050
51enc_is_odd(Enc) ->
52 case Enc of
53 1 -> 1;
54 _ -> 0
55 end.
56
Harald Welte2b4b2672011-02-03 12:50:41 +010057parse_gt(BinGT, GTind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010058 case GTind of
59 ?SCCP_GTI_NO_GT ->
Harald Welte2b4b2672011-02-03 12:50:41 +010060 undef;
Harald Welteba6fdbb2011-01-23 22:04:39 +010061 ?SCCP_GTI_NAT_ONLY ->
62 % Figure 7/Q.713
63 <<Odd:1, Nature:7, Digits/binary>> = BinGT,
64 PhoneNum = isup_codec:parse_isup_party(Digits, Odd),
Harald Welte2b4b2672011-02-03 12:50:41 +010065 #global_title{gti = GTind,
66 nature_of_addr_ind = Nature,
67 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010068 ?SCCP_GTI_TT_ONLY ->
69 % Figure 9/Q.913
70 <<TransType:8, Digits/binary>> = BinGT,
71 % Used in national interfaces only, we cannot parse Digits
Harald Welte2b4b2672011-02-03 12:50:41 +010072 #global_title{gti = GTind,
73 trans_type = TransType,
74 phone_number = Digits};
Harald Welteba6fdbb2011-01-23 22:04:39 +010075 ?SCCP_GTI_TT_NP_ENC ->
76 % Figure 10/Q.713
77 <<TransType:8, NumPlan:4, Enc:4, Digits/binary>> = BinGT,
78 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010079 #global_title{gti = GTind,
80 trans_type = TransType, encoding = Enc,
81 numbering_plan = NumPlan,
82 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010083 ?SCCP_GTI_TT_NP_ENC_NAT ->
84 % Figure 11/Q.713
85 <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, Digits/binary>> = BinGT,
86 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010087 #global_title{gti = GTind,
88 trans_type = TransType, encoding = Enc,
89 numbering_plan = NumPlan,
90 nature_of_addr_ind = Nature,
91 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010092 _ ->
Harald Welte2b4b2672011-02-03 12:50:41 +010093 BinGT
94 end.
Harald Welteba6fdbb2011-01-23 22:04:39 +010095
96% parse SCCP Address
97parse_sccp_addr(BinAddr) when is_binary(BinAddr) ->
98 <<ResNatUse:1, RoutInd:1, GTind:4, SSNind:1, PCind:1, Remain/binary>> = BinAddr,
Harald Welte2b4b2672011-02-03 12:50:41 +010099 {RemainPC, OptPC} = parse_point_code(Remain, PCind),
100 {RemainSSN, OptSSN} = parse_ssn(RemainPC, SSNind),
101 OptGT = parse_gt(RemainSSN, GTind),
102 #sccp_addr{res_nat_use = ResNatUse, route_on_ssn = RoutInd,
103 point_code = OptPC, ssn = OptSSN, global_title = OptGT}.
Harald Welte033cef02010-12-19 22:47:14 +0100104
105% parse SCCP Optional Part
106parse_sccp_opt(OptType, OptLen, Content) ->
107 {OptType, {OptLen, Content}}.
108
109parse_sccp_opts(<<>>, OptList) ->
110 % empty list
111 OptList;
112parse_sccp_opts(<<0>>, OptList) ->
113 % end of options
114 OptList;
115parse_sccp_opts(OptBin, OptList) ->
116 <<OptType, OptLen, Content:OptLen/binary, Remain/binary>> = OptBin,
117 NewOpt = parse_sccp_opt(OptType, OptLen, Content),
118 parse_sccp_opts(Remain, [NewOpt|OptList]).
119
120% Parse incoming SCCP message, one function for every message type
121parse_sccp_msgt(?SCCP_MSGT_CR, DataBin) ->
122 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200123 <<_:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, RemainVar/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100124 % variable length fixed part
125 <<PtrVar:8, PtrOpt:8, _/binary>> = RemainVar,
126 CalledPartyLen = binary:at(RemainVar, PtrVar),
127 CalledParty = binary:part(RemainVar, PtrVar+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100128 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100129 % optional part
130 OptBin = binary:part(RemainVar, 1 + PtrOpt, byte_size(RemainVar)-(1+PtrOpt)),
131 OptList = parse_sccp_opts(OptBin, []),
132 %OptList = [],
133 % build parsed list of message
Harald Welte11565772011-04-15 10:37:57 +0200134 [{src_local_ref, SrcLocalRef},{protocol_class, {ProtoClass, PCOpt}},
135 {called_party_addr, CalledPartyDec} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100136parse_sccp_msgt(?SCCP_MSGT_CC, DataBin) ->
137 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200138 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100139 % optional part
140 OptList = parse_sccp_opts(Remain, []),
141 % build parsed list of message
Harald Welte11565772011-04-15 10:37:57 +0200142 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
143 {protocol_class, {ProtoClass, PCOpt}} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100144parse_sccp_msgt(?SCCP_MSGT_CREF, DataBin) ->
145 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100146 <<_:8, DstLocalRef:24/big, RefusalCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100147 % optional part
148 OptList = parse_sccp_opts(Remain, []),
149 % build parsed list of message
150 [{dst_local_ref, DstLocalRef},{refusal_cause, RefusalCause}|OptList];
151parse_sccp_msgt(?SCCP_MSGT_RLSD, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100152 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100153 % optional part
154 OptList = parse_sccp_opts(Remain, []),
155 % build parsed list of message
156 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{release_cause, ReleaseCause}|OptList];
157parse_sccp_msgt(?SCCP_MSGT_RLC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100158 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100159 % build parsed list of message
160 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
161parse_sccp_msgt(?SCCP_MSGT_DT1, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100162 <<_:8, DstLocalRef:24/big, SegmReass:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100163 DataLen = binary:at(Remain, DataPtr-1),
164 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
165 % build parsed list of message
166 [{dst_local_ref, DstLocalRef},{segm_reass, SegmReass},{user_data, UserData}];
167parse_sccp_msgt(?SCCP_MSGT_DT2, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100168 <<_:8, DstLocalRef:24/big, SeqSegm:16, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100169 DataLen = binary:at(Remain, DataPtr-1),
170 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
171 % build parsed list of message
172 [{dst_local_ref, DstLocalRef},{seq_segm, SeqSegm},{user_data, UserData}];
173parse_sccp_msgt(?SCCP_MSGT_AK, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100174 <<_:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100175 [{dst_local_ref, DstLocalRef},{rx_seq_nr, RxSeqnr},{credit, Credit}];
176parse_sccp_msgt(?SCCP_MSGT_UDT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200177 <<_:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100178 % variable part
179 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
180 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100181 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100182 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
183 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100184 CallingPartyDec = parse_sccp_addr(CallingParty),
Harald Welte033cef02010-12-19 22:47:14 +0100185 DataLen = binary:at(Remain, DataPtr-1),
186 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
Harald Welte11565772011-04-15 10:37:57 +0200187 [{protocol_class, {ProtoClass, PCOpt}},{called_party_addr, CalledPartyDec},
Harald Welte234c9562011-02-03 13:51:12 +0100188 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100189parse_sccp_msgt(?SCCP_MSGT_UDTS, DataBin) ->
Harald Welte030f1092011-03-11 19:08:07 +0100190 <<_:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
191 % variable part
192 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
193 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
194 CalledPartyDec = parse_sccp_addr(CalledParty),
195 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
196 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
197 CallingPartyDec = parse_sccp_addr(CallingParty),
198 DataLen = binary:at(Remain, DataPtr-1),
199 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
200 [{return_cause, ReturnCause},{called_party_addr, CalledPartyDec},
201 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100202parse_sccp_msgt(?SCCP_MSGT_ED, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100203 <<_:8, DstLocalRef:24/big, DataPtr:8, Remain/binary>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100204 DataLen = binary:at(Remain, DataPtr-1),
205 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
206 [{dst_local_ref, DstLocalRef}, {user_data, UserData}];
207parse_sccp_msgt(?SCCP_MSGT_EA, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100208 <<_:8, DstLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100209 [{dst_local_ref, DstLocalRef}];
210parse_sccp_msgt(?SCCP_MSGT_RSR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100211 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100212 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{reset_cause, ResetCause}];
213parse_sccp_msgt(?SCCP_MSGT_RSC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100214 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100215 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
216parse_sccp_msgt(?SCCP_MSGT_ERR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100217 <<_:8, DstLocalRef:24/big, ErrCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100218 [{dst_local_ref, DstLocalRef},{error_cause, ErrCause}];
219parse_sccp_msgt(?SCCP_MSGT_IT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200220 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt: 4, ProtoClass:4, SegmSeq:16, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100221 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
Harald Welte11565772011-04-15 10:37:57 +0200222 {protocol_class, {ProtoClass, PCOpt}},{seq_segm, SegmSeq},{credit, Credit}].
Harald Welte033cef02010-12-19 22:47:14 +0100223% FIXME: XUDT/XUDTS, LUDT/LUDTS
224
225% process one incoming SCCP message
226parse_sccp_msg(DataBin) ->
227 MsgType = binary:first(DataBin),
228 Parsed = parse_sccp_msgt(MsgType, DataBin),
229 {ok, #sccp_msg{msg_type = MsgType, parameters = Parsed}}.
230
231% Encoding Part
232
Harald Welte0e1709c2011-02-06 22:17:53 +0100233gt_enc_by_odd(Odd) ->
234 if Odd == 1 ->
235 1;
236 true ->
237 2
238 end.
239
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200240encode_gt(undefined) ->
241 {?SCCP_GTI_NO_GT, <<>>};
Harald Welte234c9562011-02-03 13:51:12 +0100242encode_gt(#global_title{gti = GTind, phone_number = PhoneNum,
243 nature_of_addr_ind = Nature,
Harald Welte0e1709c2011-02-06 22:17:53 +0100244 trans_type = TransType, encoding = _EncOrig,
Harald Welte234c9562011-02-03 13:51:12 +0100245 numbering_plan = NumPlan}) ->
246 case GTind of
247 ?SCCP_GTI_NO_GT ->
248 {GTind, <<>>};
249 ?SCCP_GTI_NAT_ONLY ->
250 % Figure 7/Q.713
251 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
252 {GTind, <<OddEven:1, Nature:7, PhoneBin/binary>>};
253 ?SCCP_GTI_TT_ONLY ->
254 % Figure 9/Q.913
255 % Used in national interfaces only, we cannot parse Digits
256 {GTind, <<TransType:8, PhoneNum/binary>>};
257 ?SCCP_GTI_TT_NP_ENC ->
258 % Figure 10/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100259 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
260 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100261 {GTind, <<TransType:8, NumPlan:4, Enc:4, PhoneBin/binary>>};
262 ?SCCP_GTI_TT_NP_ENC_NAT ->
263 % Figure 11/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100264 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
265 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100266 {GTind, <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, PhoneBin/binary>>}
267 end.
268
269encode_pc(PointCode) ->
270 case PointCode of
271 undef ->
272 {0, <<>>};
273 _ ->
274 {1, <<PointCode:16/big>>}
275 end.
276
277encode_ssn(SSN) ->
278 case SSN of
279 undef ->
280 {0, <<>>};
281 _ ->
282 {1, <<SSN:8>>}
283 end.
284
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200285undef_or_true(Foo) ->
286 case Foo of
287 undefined -> 0;
288 0 -> 0;
289 _ -> 1
290 end.
291
292
Harald Welte234c9562011-02-03 13:51:12 +0100293encode_sccp_addr(#sccp_addr{res_nat_use = ResNatUse,
294 route_on_ssn = RoutInd,
295 point_code = PointCode,
296 ssn = SSN,
297 global_title = GT}) ->
298
299 {GTind, GTbin} = encode_gt(GT),
300 {SSNind, SSNbin} = encode_ssn(SSN),
301 {PCind, PCbin} = encode_pc(PointCode),
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200302 ResNatOut = undef_or_true(ResNatUse),
303 RoutIndOut = undef_or_true(RoutInd),
304 <<ResNatOut:1, RoutIndOut:1, GTind:4, SSNind:1, PCind:1, PCbin/binary, SSNbin/binary, GTbin/binary>>.
Harald Welte234c9562011-02-03 13:51:12 +0100305
306
Harald Welte033cef02010-12-19 22:47:14 +0100307encode_sccp_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
308 DataBinLen8 = DataBinLen*8,
309 <<OptNum:8, DataBinLen:8, DataBin:DataBinLen8>>;
310encode_sccp_opt({OptAtom,_}) when is_atom(OptAtom) ->
311 <<>>.
312
313encode_sccp_opts([], OptEnc) ->
314 % end of options + convert to binary
315 list_to_binary([OptEnc, ?SCCP_PNC_END_OF_OPTIONAL]);
316encode_sccp_opts([CurOpt|OptPropList], OptEnc) ->
317 CurOptEnc = encode_sccp_opt(CurOpt),
318 encode_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
319
320
321
322encode_sccp_msgt(?SCCP_MSGT_CR, Params) ->
323 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200324 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100325 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200326 <<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100327encode_sccp_msgt(?SCCP_MSGT_CC, Params) ->
328 SrcLocalRef = proplists:get_value(src_local_ref, Params),
329 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200330 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100331 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200332 <<?SCCP_MSGT_CC:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100333encode_sccp_msgt(?SCCP_MSGT_CREF, Params) ->
334 DstLocalRef = proplists:get_value(dst_local_ref, Params),
335 RefusalCause = proplists:get_value(refusal_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100336 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100337 <<?SCCP_MSGT_CREF:8, DstLocalRef:24/big, RefusalCause:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100338encode_sccp_msgt(?SCCP_MSGT_RLSD, Params) ->
339 SrcLocalRef = proplists:get_value(src_local_ref, Params),
340 DstLocalRef = proplists:get_value(dst_local_ref, Params),
341 ReleaseCause = proplists:get_value(release_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100342 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100343 <<?SCCP_MSGT_RLSD:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, OptBin/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100344encode_sccp_msgt(?SCCP_MSGT_RLC, Params) ->
345 SrcLocalRef = proplists:get_value(src_local_ref, Params),
346 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100347 <<?SCCP_MSGT_RLC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100348encode_sccp_msgt(?SCCP_MSGT_DT1, Params) ->
349 DstLocalRef = proplists:get_value(dst_local_ref, Params),
350 SegmReass = proplists:get_value(segm_reass, Params),
351 UserData = proplists:get_value(user_data, Params),
352 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100353 <<?SCCP_MSGT_DT1:8, DstLocalRef:24/big, SegmReass:8, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100354encode_sccp_msgt(?SCCP_MSGT_DT2, Params) ->
355 DstLocalRef = proplists:get_value(dst_local_ref, Params),
356 SeqSegm = proplists:get_value(seq_segm, Params),
357 UserData = proplists:get_value(user_data, Params),
358 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100359 <<?SCCP_MSGT_DT2:8, DstLocalRef:24/big, SeqSegm:16, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100360encode_sccp_msgt(?SCCP_MSGT_AK, Params) ->
361 DstLocalRef = proplists:get_value(dst_local_ref, Params),
362 RxSeqnr = proplists:get_value(rx_seqnr, Params),
363 Credit = proplists:get_value(credit, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100364 <<?SCCP_MSGT_AK:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100365encode_sccp_msgt(?SCCP_MSGT_UDT, Params) ->
Harald Welte11565772011-04-15 10:37:57 +0200366 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100367 CalledParty = proplists:get_value(called_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100368 CalledPartyEnc = encode_sccp_addr(CalledParty),
369 CalledPartyLen = byte_size(CalledPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100370 CallingParty = proplists:get_value(calling_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100371 CallingPartyEnc = encode_sccp_addr(CallingParty),
372 CallingPartyLen = byte_size(CallingPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100373 UserData = proplists:get_value(user_data, Params),
374 UserDataLen = byte_size(UserData),
375 % variable part
376 CalledPartyPtr = 3,
377 CallingPartyPtr = 2 + (1 + CalledPartyLen),
378 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100379 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
380 CallingPartyLen:8, CallingPartyEnc/binary,
Harald Weltec0696b02010-12-20 00:09:37 +0100381 UserDataLen:8, UserData/binary>>,
Harald Welte11565772011-04-15 10:37:57 +0200382 <<?SCCP_MSGT_UDT:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Welte030f1092011-03-11 19:08:07 +0100383encode_sccp_msgt(?SCCP_MSGT_UDTS, Params) ->
384 ReturnCause = proplists:get_value(return_cause, Params),
385 CalledParty = proplists:get_value(called_party_addr, Params),
386 CalledPartyEnc = encode_sccp_addr(CalledParty),
387 CalledPartyLen = byte_size(CalledPartyEnc),
388 CallingParty = proplists:get_value(calling_party_addr, Params),
389 CallingPartyEnc = encode_sccp_addr(CallingParty),
390 CallingPartyLen = byte_size(CallingPartyEnc),
391 UserData = proplists:get_value(user_data, Params),
392 UserDataLen = byte_size(UserData),
393 % variable part
394 CalledPartyPtr = 3,
395 CallingPartyPtr = 2 + (1 + CalledPartyLen),
396 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
397 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
398 CallingPartyLen:8, CallingPartyEnc/binary,
399 UserDataLen:8, UserData/binary>>,
400 <<?SCCP_MSGT_UDTS:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100401encode_sccp_msgt(?SCCP_MSGT_ED, Params) ->
402 DstLocalRef = proplists:get_value(dst_local_ref, Params),
403 UserData = proplists:get_value(user_data, Params),
404 UserDataLen = byte_size(UserData),
405 DataPtr = 1,
Harald Welte56ee7a62010-12-20 13:34:32 +0100406 <<?SCCP_MSGT_ED:8, DstLocalRef:24/big, DataPtr:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100407encode_sccp_msgt(?SCCP_MSGT_EA, Params) ->
408 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100409 <<?SCCP_MSGT_EA:8, DstLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100410encode_sccp_msgt(?SCCP_MSGT_RSR, Params) ->
411 DstLocalRef = proplists:get_value(dst_local_ref, Params),
412 SrcLocalRef = proplists:get_value(src_local_ref, Params),
413 ResetCause = proplists:get_value(reset_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100414 <<?SCCP_MSGT_RSR:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100415encode_sccp_msgt(?SCCP_MSGT_RSC, Params) ->
416 DstLocalRef = proplists:get_value(dst_local_ref, Params),
417 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100418 <<?SCCP_MSGT_RSC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100419encode_sccp_msgt(?SCCP_MSGT_ERR, Params) ->
420 DstLocalRef = proplists:get_value(dst_local_ref, Params),
421 ErrCause = proplists:get_value(error_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100422 <<?SCCP_MSGT_ERR:8, DstLocalRef:24/big, ErrCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100423encode_sccp_msgt(?SCCP_MSGT_IT, Params) ->
424 DstLocalRef = proplists:get_value(dst_local_ref, Params),
425 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200426 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte09b43992010-12-20 12:21:03 +0100427 SegmSeq = proplists:get_value(seq_segm, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100428 Credit = proplists:get_value(credit, Params),
Harald Welte11565772011-04-15 10:37:57 +0200429 <<?SCCP_MSGT_IT:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, SegmSeq:16, Credit:8>>.
Harald Weltec0696b02010-12-20 00:09:37 +0100430% FIXME: XUDT/XUDTS, LUDT/LUDTS
431
Harald Welte033cef02010-12-19 22:47:14 +0100432
433% encode one sccp message data structure into the on-wire format
434encode_sccp_msg(#sccp_msg{msg_type = MsgType, parameters = Params}) ->
435 encode_sccp_msgt(MsgType, Params).