blob: 25ad05bd36e210611d1521d99741ae63a63568e0 [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
Harald Welte9abbbad2011-04-21 12:19:41 +020024-export([parse_sccp_msg/1, encode_sccp_msg/1, encode_sccp_msgt/2,
25 is_connectionless/1]).
Harald Welte033cef02010-12-19 22:47:14 +010026
27-compile(export_all).
28
Harald Welte2edaf552011-04-02 16:46:16 +020029-compile({parse_transform, exprecs}).
Harald Welte0f2f5962011-04-04 15:59:49 +020030-export_records([global_title, sccp_addr, sccp_msg]).
Harald Welte2edaf552011-04-02 16:46:16 +020031
Harald Welte2b4b2672011-02-03 12:50:41 +010032parse_point_code(BinPC, PCind) when is_binary(BinPC) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010033 case PCind of
34 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010035 <<PointCode:16/big, Remain/binary>> = BinPC;
Harald Welteba6fdbb2011-01-23 22:04:39 +010036 _ ->
37 Remain = BinPC,
Harald Welte2b4b2672011-02-03 12:50:41 +010038 PointCode = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010039 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010040 {Remain, PointCode}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010041
Harald Welte2b4b2672011-02-03 12:50:41 +010042parse_ssn(BinSSN, SSNind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010043 case SSNind of
44 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010045 <<SSN:8, Remain/binary>> = BinSSN;
Harald Welteba6fdbb2011-01-23 22:04:39 +010046 _ ->
47 Remain = BinSSN,
Harald Welte2b4b2672011-02-03 12:50:41 +010048 SSN = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010049 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010050 {Remain, SSN}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010051
52enc_is_odd(Enc) ->
53 case Enc of
54 1 -> 1;
55 _ -> 0
56 end.
57
Harald Welte2b4b2672011-02-03 12:50:41 +010058parse_gt(BinGT, GTind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010059 case GTind of
60 ?SCCP_GTI_NO_GT ->
Harald Welte2b4b2672011-02-03 12:50:41 +010061 undef;
Harald Welteba6fdbb2011-01-23 22:04:39 +010062 ?SCCP_GTI_NAT_ONLY ->
63 % Figure 7/Q.713
64 <<Odd:1, Nature:7, Digits/binary>> = BinGT,
65 PhoneNum = isup_codec:parse_isup_party(Digits, Odd),
Harald Welte2b4b2672011-02-03 12:50:41 +010066 #global_title{gti = GTind,
67 nature_of_addr_ind = Nature,
68 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010069 ?SCCP_GTI_TT_ONLY ->
70 % Figure 9/Q.913
71 <<TransType:8, Digits/binary>> = BinGT,
72 % Used in national interfaces only, we cannot parse Digits
Harald Welte2b4b2672011-02-03 12:50:41 +010073 #global_title{gti = GTind,
74 trans_type = TransType,
75 phone_number = Digits};
Harald Welteba6fdbb2011-01-23 22:04:39 +010076 ?SCCP_GTI_TT_NP_ENC ->
77 % Figure 10/Q.713
78 <<TransType:8, NumPlan:4, Enc:4, Digits/binary>> = BinGT,
79 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010080 #global_title{gti = GTind,
81 trans_type = TransType, encoding = Enc,
82 numbering_plan = NumPlan,
83 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010084 ?SCCP_GTI_TT_NP_ENC_NAT ->
85 % Figure 11/Q.713
86 <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, Digits/binary>> = BinGT,
87 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010088 #global_title{gti = GTind,
89 trans_type = TransType, encoding = Enc,
90 numbering_plan = NumPlan,
91 nature_of_addr_ind = Nature,
92 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010093 _ ->
Harald Welte2b4b2672011-02-03 12:50:41 +010094 BinGT
95 end.
Harald Welteba6fdbb2011-01-23 22:04:39 +010096
97% parse SCCP Address
98parse_sccp_addr(BinAddr) when is_binary(BinAddr) ->
99 <<ResNatUse:1, RoutInd:1, GTind:4, SSNind:1, PCind:1, Remain/binary>> = BinAddr,
Harald Welte2b4b2672011-02-03 12:50:41 +0100100 {RemainPC, OptPC} = parse_point_code(Remain, PCind),
101 {RemainSSN, OptSSN} = parse_ssn(RemainPC, SSNind),
102 OptGT = parse_gt(RemainSSN, GTind),
103 #sccp_addr{res_nat_use = ResNatUse, route_on_ssn = RoutInd,
104 point_code = OptPC, ssn = OptSSN, global_title = OptGT}.
Harald Welte033cef02010-12-19 22:47:14 +0100105
106% parse SCCP Optional Part
107parse_sccp_opt(OptType, OptLen, Content) ->
108 {OptType, {OptLen, Content}}.
109
110parse_sccp_opts(<<>>, OptList) ->
111 % empty list
112 OptList;
113parse_sccp_opts(<<0>>, OptList) ->
114 % end of options
115 OptList;
116parse_sccp_opts(OptBin, OptList) ->
117 <<OptType, OptLen, Content:OptLen/binary, Remain/binary>> = OptBin,
118 NewOpt = parse_sccp_opt(OptType, OptLen, Content),
119 parse_sccp_opts(Remain, [NewOpt|OptList]).
120
121% Parse incoming SCCP message, one function for every message type
122parse_sccp_msgt(?SCCP_MSGT_CR, DataBin) ->
123 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200124 <<_:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, RemainVar/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100125 % variable length fixed part
126 <<PtrVar:8, PtrOpt:8, _/binary>> = RemainVar,
127 CalledPartyLen = binary:at(RemainVar, PtrVar),
128 CalledParty = binary:part(RemainVar, PtrVar+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100129 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100130 % optional part
131 OptBin = binary:part(RemainVar, 1 + PtrOpt, byte_size(RemainVar)-(1+PtrOpt)),
132 OptList = parse_sccp_opts(OptBin, []),
133 %OptList = [],
134 % build parsed list of message
Harald Welte11565772011-04-15 10:37:57 +0200135 [{src_local_ref, SrcLocalRef},{protocol_class, {ProtoClass, PCOpt}},
136 {called_party_addr, CalledPartyDec} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100137parse_sccp_msgt(?SCCP_MSGT_CC, DataBin) ->
138 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200139 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100140 % optional part
141 OptList = parse_sccp_opts(Remain, []),
142 % build parsed list of message
Harald Welte11565772011-04-15 10:37:57 +0200143 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
144 {protocol_class, {ProtoClass, PCOpt}} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100145parse_sccp_msgt(?SCCP_MSGT_CREF, DataBin) ->
146 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100147 <<_:8, DstLocalRef:24/big, RefusalCause: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},{refusal_cause, RefusalCause}|OptList];
152parse_sccp_msgt(?SCCP_MSGT_RLSD, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100153 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100154 % optional part
155 OptList = parse_sccp_opts(Remain, []),
156 % build parsed list of message
157 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{release_cause, ReleaseCause}|OptList];
158parse_sccp_msgt(?SCCP_MSGT_RLC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100159 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100160 % build parsed list of message
161 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
162parse_sccp_msgt(?SCCP_MSGT_DT1, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100163 <<_:8, DstLocalRef:24/big, SegmReass:8, 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},{segm_reass, SegmReass},{user_data, UserData}];
168parse_sccp_msgt(?SCCP_MSGT_DT2, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100169 <<_:8, DstLocalRef:24/big, SeqSegm:16, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100170 DataLen = binary:at(Remain, DataPtr-1),
171 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
172 % build parsed list of message
173 [{dst_local_ref, DstLocalRef},{seq_segm, SeqSegm},{user_data, UserData}];
174parse_sccp_msgt(?SCCP_MSGT_AK, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100175 <<_:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100176 [{dst_local_ref, DstLocalRef},{rx_seq_nr, RxSeqnr},{credit, Credit}];
177parse_sccp_msgt(?SCCP_MSGT_UDT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200178 <<_:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100179 % variable part
180 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
181 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100182 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100183 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
184 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100185 CallingPartyDec = parse_sccp_addr(CallingParty),
Harald Welte033cef02010-12-19 22:47:14 +0100186 DataLen = binary:at(Remain, DataPtr-1),
187 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
Harald Welte11565772011-04-15 10:37:57 +0200188 [{protocol_class, {ProtoClass, PCOpt}},{called_party_addr, CalledPartyDec},
Harald Welte234c9562011-02-03 13:51:12 +0100189 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100190parse_sccp_msgt(?SCCP_MSGT_UDTS, DataBin) ->
Harald Welte030f1092011-03-11 19:08:07 +0100191 <<_:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
192 % variable part
193 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
194 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
195 CalledPartyDec = parse_sccp_addr(CalledParty),
196 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
197 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
198 CallingPartyDec = parse_sccp_addr(CallingParty),
199 DataLen = binary:at(Remain, DataPtr-1),
200 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
201 [{return_cause, ReturnCause},{called_party_addr, CalledPartyDec},
202 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100203parse_sccp_msgt(?SCCP_MSGT_ED, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100204 <<_:8, DstLocalRef:24/big, DataPtr:8, Remain/binary>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100205 DataLen = binary:at(Remain, DataPtr-1),
206 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
207 [{dst_local_ref, DstLocalRef}, {user_data, UserData}];
208parse_sccp_msgt(?SCCP_MSGT_EA, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100209 <<_:8, DstLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100210 [{dst_local_ref, DstLocalRef}];
211parse_sccp_msgt(?SCCP_MSGT_RSR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100212 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100213 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{reset_cause, ResetCause}];
214parse_sccp_msgt(?SCCP_MSGT_RSC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100215 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100216 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
217parse_sccp_msgt(?SCCP_MSGT_ERR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100218 <<_:8, DstLocalRef:24/big, ErrCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100219 [{dst_local_ref, DstLocalRef},{error_cause, ErrCause}];
220parse_sccp_msgt(?SCCP_MSGT_IT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200221 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt: 4, ProtoClass:4, SegmSeq:16, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100222 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
Harald Welte11565772011-04-15 10:37:57 +0200223 {protocol_class, {ProtoClass, PCOpt}},{seq_segm, SegmSeq},{credit, Credit}].
Harald Welte033cef02010-12-19 22:47:14 +0100224% FIXME: XUDT/XUDTS, LUDT/LUDTS
225
226% process one incoming SCCP message
227parse_sccp_msg(DataBin) ->
228 MsgType = binary:first(DataBin),
229 Parsed = parse_sccp_msgt(MsgType, DataBin),
230 {ok, #sccp_msg{msg_type = MsgType, parameters = Parsed}}.
231
232% Encoding Part
233
Harald Welte0e1709c2011-02-06 22:17:53 +0100234gt_enc_by_odd(Odd) ->
235 if Odd == 1 ->
236 1;
237 true ->
238 2
239 end.
240
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200241encode_gt(undefined) ->
242 {?SCCP_GTI_NO_GT, <<>>};
Harald Welte234c9562011-02-03 13:51:12 +0100243encode_gt(#global_title{gti = GTind, phone_number = PhoneNum,
244 nature_of_addr_ind = Nature,
Harald Welte0e1709c2011-02-06 22:17:53 +0100245 trans_type = TransType, encoding = _EncOrig,
Harald Welte234c9562011-02-03 13:51:12 +0100246 numbering_plan = NumPlan}) ->
247 case GTind of
248 ?SCCP_GTI_NO_GT ->
249 {GTind, <<>>};
250 ?SCCP_GTI_NAT_ONLY ->
251 % Figure 7/Q.713
252 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
253 {GTind, <<OddEven:1, Nature:7, PhoneBin/binary>>};
254 ?SCCP_GTI_TT_ONLY ->
255 % Figure 9/Q.913
256 % Used in national interfaces only, we cannot parse Digits
257 {GTind, <<TransType:8, PhoneNum/binary>>};
258 ?SCCP_GTI_TT_NP_ENC ->
259 % Figure 10/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100260 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
261 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100262 {GTind, <<TransType:8, NumPlan:4, Enc:4, PhoneBin/binary>>};
263 ?SCCP_GTI_TT_NP_ENC_NAT ->
264 % Figure 11/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100265 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
266 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100267 {GTind, <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, PhoneBin/binary>>}
268 end.
269
270encode_pc(PointCode) ->
271 case PointCode of
272 undef ->
273 {0, <<>>};
274 _ ->
275 {1, <<PointCode:16/big>>}
276 end.
277
278encode_ssn(SSN) ->
279 case SSN of
280 undef ->
281 {0, <<>>};
282 _ ->
283 {1, <<SSN:8>>}
284 end.
285
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200286undef_or_true(Foo) ->
287 case Foo of
288 undefined -> 0;
289 0 -> 0;
290 _ -> 1
291 end.
292
293
Harald Welte234c9562011-02-03 13:51:12 +0100294encode_sccp_addr(#sccp_addr{res_nat_use = ResNatUse,
295 route_on_ssn = RoutInd,
296 point_code = PointCode,
297 ssn = SSN,
298 global_title = GT}) ->
299
300 {GTind, GTbin} = encode_gt(GT),
301 {SSNind, SSNbin} = encode_ssn(SSN),
302 {PCind, PCbin} = encode_pc(PointCode),
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200303 ResNatOut = undef_or_true(ResNatUse),
304 RoutIndOut = undef_or_true(RoutInd),
305 <<ResNatOut:1, RoutIndOut:1, GTind:4, SSNind:1, PCind:1, PCbin/binary, SSNbin/binary, GTbin/binary>>.
Harald Welte234c9562011-02-03 13:51:12 +0100306
307
Harald Welte033cef02010-12-19 22:47:14 +0100308encode_sccp_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
309 DataBinLen8 = DataBinLen*8,
310 <<OptNum:8, DataBinLen:8, DataBin:DataBinLen8>>;
311encode_sccp_opt({OptAtom,_}) when is_atom(OptAtom) ->
312 <<>>.
313
314encode_sccp_opts([], OptEnc) ->
315 % end of options + convert to binary
316 list_to_binary([OptEnc, ?SCCP_PNC_END_OF_OPTIONAL]);
317encode_sccp_opts([CurOpt|OptPropList], OptEnc) ->
318 CurOptEnc = encode_sccp_opt(CurOpt),
319 encode_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
320
321
322
323encode_sccp_msgt(?SCCP_MSGT_CR, Params) ->
324 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200325 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100326 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200327 <<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100328encode_sccp_msgt(?SCCP_MSGT_CC, Params) ->
329 SrcLocalRef = proplists:get_value(src_local_ref, Params),
330 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200331 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100332 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200333 <<?SCCP_MSGT_CC:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100334encode_sccp_msgt(?SCCP_MSGT_CREF, Params) ->
335 DstLocalRef = proplists:get_value(dst_local_ref, Params),
336 RefusalCause = proplists:get_value(refusal_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100337 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100338 <<?SCCP_MSGT_CREF:8, DstLocalRef:24/big, RefusalCause:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100339encode_sccp_msgt(?SCCP_MSGT_RLSD, Params) ->
340 SrcLocalRef = proplists:get_value(src_local_ref, Params),
341 DstLocalRef = proplists:get_value(dst_local_ref, Params),
342 ReleaseCause = proplists:get_value(release_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100343 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100344 <<?SCCP_MSGT_RLSD:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, OptBin/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100345encode_sccp_msgt(?SCCP_MSGT_RLC, Params) ->
346 SrcLocalRef = proplists:get_value(src_local_ref, Params),
347 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100348 <<?SCCP_MSGT_RLC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100349encode_sccp_msgt(?SCCP_MSGT_DT1, Params) ->
350 DstLocalRef = proplists:get_value(dst_local_ref, Params),
351 SegmReass = proplists:get_value(segm_reass, Params),
352 UserData = proplists:get_value(user_data, Params),
353 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100354 <<?SCCP_MSGT_DT1:8, DstLocalRef:24/big, SegmReass:8, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100355encode_sccp_msgt(?SCCP_MSGT_DT2, Params) ->
356 DstLocalRef = proplists:get_value(dst_local_ref, Params),
357 SeqSegm = proplists:get_value(seq_segm, Params),
358 UserData = proplists:get_value(user_data, Params),
359 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100360 <<?SCCP_MSGT_DT2:8, DstLocalRef:24/big, SeqSegm:16, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100361encode_sccp_msgt(?SCCP_MSGT_AK, Params) ->
362 DstLocalRef = proplists:get_value(dst_local_ref, Params),
363 RxSeqnr = proplists:get_value(rx_seqnr, Params),
364 Credit = proplists:get_value(credit, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100365 <<?SCCP_MSGT_AK:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100366encode_sccp_msgt(?SCCP_MSGT_UDT, Params) ->
Harald Welte11565772011-04-15 10:37:57 +0200367 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100368 CalledParty = proplists:get_value(called_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100369 CalledPartyEnc = encode_sccp_addr(CalledParty),
370 CalledPartyLen = byte_size(CalledPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100371 CallingParty = proplists:get_value(calling_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100372 CallingPartyEnc = encode_sccp_addr(CallingParty),
373 CallingPartyLen = byte_size(CallingPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100374 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),
Harald Welte234c9562011-02-03 13:51:12 +0100380 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
381 CallingPartyLen:8, CallingPartyEnc/binary,
Harald Weltec0696b02010-12-20 00:09:37 +0100382 UserDataLen:8, UserData/binary>>,
Harald Welte11565772011-04-15 10:37:57 +0200383 <<?SCCP_MSGT_UDT:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Welte030f1092011-03-11 19:08:07 +0100384encode_sccp_msgt(?SCCP_MSGT_UDTS, Params) ->
385 ReturnCause = proplists:get_value(return_cause, Params),
386 CalledParty = proplists:get_value(called_party_addr, Params),
387 CalledPartyEnc = encode_sccp_addr(CalledParty),
388 CalledPartyLen = byte_size(CalledPartyEnc),
389 CallingParty = proplists:get_value(calling_party_addr, Params),
390 CallingPartyEnc = encode_sccp_addr(CallingParty),
391 CallingPartyLen = byte_size(CallingPartyEnc),
392 UserData = proplists:get_value(user_data, Params),
393 UserDataLen = byte_size(UserData),
394 % variable part
395 CalledPartyPtr = 3,
396 CallingPartyPtr = 2 + (1 + CalledPartyLen),
397 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
398 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
399 CallingPartyLen:8, CallingPartyEnc/binary,
400 UserDataLen:8, UserData/binary>>,
401 <<?SCCP_MSGT_UDTS:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100402encode_sccp_msgt(?SCCP_MSGT_ED, Params) ->
403 DstLocalRef = proplists:get_value(dst_local_ref, Params),
404 UserData = proplists:get_value(user_data, Params),
405 UserDataLen = byte_size(UserData),
406 DataPtr = 1,
Harald Welte56ee7a62010-12-20 13:34:32 +0100407 <<?SCCP_MSGT_ED:8, DstLocalRef:24/big, DataPtr:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100408encode_sccp_msgt(?SCCP_MSGT_EA, Params) ->
409 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100410 <<?SCCP_MSGT_EA:8, DstLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100411encode_sccp_msgt(?SCCP_MSGT_RSR, Params) ->
412 DstLocalRef = proplists:get_value(dst_local_ref, Params),
413 SrcLocalRef = proplists:get_value(src_local_ref, Params),
414 ResetCause = proplists:get_value(reset_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100415 <<?SCCP_MSGT_RSR:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100416encode_sccp_msgt(?SCCP_MSGT_RSC, Params) ->
417 DstLocalRef = proplists:get_value(dst_local_ref, Params),
418 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100419 <<?SCCP_MSGT_RSC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100420encode_sccp_msgt(?SCCP_MSGT_ERR, Params) ->
421 DstLocalRef = proplists:get_value(dst_local_ref, Params),
422 ErrCause = proplists:get_value(error_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100423 <<?SCCP_MSGT_ERR:8, DstLocalRef:24/big, ErrCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100424encode_sccp_msgt(?SCCP_MSGT_IT, Params) ->
425 DstLocalRef = proplists:get_value(dst_local_ref, Params),
426 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200427 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte09b43992010-12-20 12:21:03 +0100428 SegmSeq = proplists:get_value(seq_segm, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100429 Credit = proplists:get_value(credit, Params),
Harald Welte11565772011-04-15 10:37:57 +0200430 <<?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 +0100431% FIXME: XUDT/XUDTS, LUDT/LUDTS
432
Harald Welte033cef02010-12-19 22:47:14 +0100433
434% encode one sccp message data structure into the on-wire format
435encode_sccp_msg(#sccp_msg{msg_type = MsgType, parameters = Params}) ->
436 encode_sccp_msgt(MsgType, Params).
Harald Welte9abbbad2011-04-21 12:19:41 +0200437
438% is the supplied message type a connectionless message?
439is_connectionless(#sccp_msg{msg_type = MsgType}) ->
440 is_connectionless(MsgType);
441is_connectionless(MsgType) ->
442 case MsgType of
443 ?SCCP_MSGT_UDT -> true;
444 ?SCCP_MSGT_UDTS -> true;
445 ?SCCP_MSGT_XUDT -> true;
446 ?SCCP_MSGT_XUDTS -> true;
447 ?SCCP_MSGT_LUDT -> true;
448 ?SCCP_MSGT_LUDTS -> true;
449 _ -> false
450 end.