blob: b3989e603ab71b74c0747f230b551f597938d12e [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
Harald Welte9baab6d2011-12-08 00:46:00 +010027-export([gen_gt_helper/1, gen_addr_helper/2, gen_addr_helper/3]).
28
Harald Welte033cef02010-12-19 22:47:14 +010029-compile(export_all).
30
Harald Welte2edaf552011-04-02 16:46:16 +020031-compile({parse_transform, exprecs}).
Harald Welte0f2f5962011-04-04 15:59:49 +020032-export_records([global_title, sccp_addr, sccp_msg]).
Harald Welte2edaf552011-04-02 16:46:16 +020033
Harald Welte2b4b2672011-02-03 12:50:41 +010034parse_point_code(BinPC, PCind) when is_binary(BinPC) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010035 case PCind of
36 1 ->
Harald Welte9c3b1bb2011-10-12 17:00:34 +020037 <<PointCode:16/little, Remain/binary>> = BinPC;
Harald Welteba6fdbb2011-01-23 22:04:39 +010038 _ ->
39 Remain = BinPC,
Harald Welte2b4b2672011-02-03 12:50:41 +010040 PointCode = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010041 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010042 {Remain, PointCode}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010043
Harald Welte2b4b2672011-02-03 12:50:41 +010044parse_ssn(BinSSN, SSNind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010045 case SSNind of
46 1 ->
Harald Welte2b4b2672011-02-03 12:50:41 +010047 <<SSN:8, Remain/binary>> = BinSSN;
Harald Welteba6fdbb2011-01-23 22:04:39 +010048 _ ->
49 Remain = BinSSN,
Harald Welte2b4b2672011-02-03 12:50:41 +010050 SSN = undef
Harald Welteba6fdbb2011-01-23 22:04:39 +010051 end,
Harald Welte2b4b2672011-02-03 12:50:41 +010052 {Remain, SSN}.
Harald Welteba6fdbb2011-01-23 22:04:39 +010053
54enc_is_odd(Enc) ->
55 case Enc of
56 1 -> 1;
57 _ -> 0
58 end.
59
Harald Welte2b4b2672011-02-03 12:50:41 +010060parse_gt(BinGT, GTind) ->
Harald Welteba6fdbb2011-01-23 22:04:39 +010061 case GTind of
62 ?SCCP_GTI_NO_GT ->
Harald Welte2b4b2672011-02-03 12:50:41 +010063 undef;
Harald Welteba6fdbb2011-01-23 22:04:39 +010064 ?SCCP_GTI_NAT_ONLY ->
65 % Figure 7/Q.713
66 <<Odd:1, Nature:7, Digits/binary>> = BinGT,
67 PhoneNum = isup_codec:parse_isup_party(Digits, Odd),
Harald Welte2b4b2672011-02-03 12:50:41 +010068 #global_title{gti = GTind,
69 nature_of_addr_ind = Nature,
70 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010071 ?SCCP_GTI_TT_ONLY ->
72 % Figure 9/Q.913
73 <<TransType:8, Digits/binary>> = BinGT,
74 % Used in national interfaces only, we cannot parse Digits
Harald Welte2b4b2672011-02-03 12:50:41 +010075 #global_title{gti = GTind,
76 trans_type = TransType,
77 phone_number = Digits};
Harald Welteba6fdbb2011-01-23 22:04:39 +010078 ?SCCP_GTI_TT_NP_ENC ->
79 % Figure 10/Q.713
80 <<TransType:8, NumPlan:4, Enc:4, Digits/binary>> = BinGT,
81 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010082 #global_title{gti = GTind,
83 trans_type = TransType, encoding = Enc,
84 numbering_plan = NumPlan,
85 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010086 ?SCCP_GTI_TT_NP_ENC_NAT ->
87 % Figure 11/Q.713
88 <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, Digits/binary>> = BinGT,
89 PhoneNum = isup_codec:parse_isup_party(Digits, enc_is_odd(Enc)),
Harald Welte2b4b2672011-02-03 12:50:41 +010090 #global_title{gti = GTind,
91 trans_type = TransType, encoding = Enc,
92 numbering_plan = NumPlan,
93 nature_of_addr_ind = Nature,
94 phone_number = PhoneNum};
Harald Welteba6fdbb2011-01-23 22:04:39 +010095 _ ->
Harald Welte2b4b2672011-02-03 12:50:41 +010096 BinGT
97 end.
Harald Welteba6fdbb2011-01-23 22:04:39 +010098
99% parse SCCP Address
100parse_sccp_addr(BinAddr) when is_binary(BinAddr) ->
101 <<ResNatUse:1, RoutInd:1, GTind:4, SSNind:1, PCind:1, Remain/binary>> = BinAddr,
Harald Welte2b4b2672011-02-03 12:50:41 +0100102 {RemainPC, OptPC} = parse_point_code(Remain, PCind),
103 {RemainSSN, OptSSN} = parse_ssn(RemainPC, SSNind),
104 OptGT = parse_gt(RemainSSN, GTind),
105 #sccp_addr{res_nat_use = ResNatUse, route_on_ssn = RoutInd,
106 point_code = OptPC, ssn = OptSSN, global_title = OptGT}.
Harald Welte033cef02010-12-19 22:47:14 +0100107
108% parse SCCP Optional Part
109parse_sccp_opt(OptType, OptLen, Content) ->
110 {OptType, {OptLen, Content}}.
111
112parse_sccp_opts(<<>>, OptList) ->
113 % empty list
114 OptList;
115parse_sccp_opts(<<0>>, OptList) ->
116 % end of options
117 OptList;
118parse_sccp_opts(OptBin, OptList) ->
119 <<OptType, OptLen, Content:OptLen/binary, Remain/binary>> = OptBin,
120 NewOpt = parse_sccp_opt(OptType, OptLen, Content),
121 parse_sccp_opts(Remain, [NewOpt|OptList]).
122
123% Parse incoming SCCP message, one function for every message type
124parse_sccp_msgt(?SCCP_MSGT_CR, DataBin) ->
125 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200126 <<_:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, RemainVar/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100127 % variable length fixed part
128 <<PtrVar:8, PtrOpt:8, _/binary>> = RemainVar,
129 CalledPartyLen = binary:at(RemainVar, PtrVar),
130 CalledParty = binary:part(RemainVar, PtrVar+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100131 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100132 % optional part
133 OptBin = binary:part(RemainVar, 1 + PtrOpt, byte_size(RemainVar)-(1+PtrOpt)),
134 OptList = parse_sccp_opts(OptBin, []),
135 %OptList = [],
136 % build parsed list of message
Harald Welte11565772011-04-15 10:37:57 +0200137 [{src_local_ref, SrcLocalRef},{protocol_class, {ProtoClass, PCOpt}},
138 {called_party_addr, CalledPartyDec} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100139parse_sccp_msgt(?SCCP_MSGT_CC, DataBin) ->
140 % first get the fixed part
Harald Welte11565772011-04-15 10:37:57 +0200141 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, 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
Harald Welte11565772011-04-15 10:37:57 +0200145 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
146 {protocol_class, {ProtoClass, PCOpt}} | OptList];
Harald Welte033cef02010-12-19 22:47:14 +0100147parse_sccp_msgt(?SCCP_MSGT_CREF, DataBin) ->
148 % first get the fixed part
Harald Welte56ee7a62010-12-20 13:34:32 +0100149 <<_:8, DstLocalRef:24/big, RefusalCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100150 % optional part
151 OptList = parse_sccp_opts(Remain, []),
152 % build parsed list of message
153 [{dst_local_ref, DstLocalRef},{refusal_cause, RefusalCause}|OptList];
154parse_sccp_msgt(?SCCP_MSGT_RLSD, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100155 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100156 % optional part
157 OptList = parse_sccp_opts(Remain, []),
158 % build parsed list of message
159 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{release_cause, ReleaseCause}|OptList];
160parse_sccp_msgt(?SCCP_MSGT_RLC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100161 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100162 % build parsed list of message
163 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
164parse_sccp_msgt(?SCCP_MSGT_DT1, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100165 <<_:8, DstLocalRef:24/big, SegmReass:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100166 DataLen = binary:at(Remain, DataPtr-1),
167 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
168 % build parsed list of message
169 [{dst_local_ref, DstLocalRef},{segm_reass, SegmReass},{user_data, UserData}];
170parse_sccp_msgt(?SCCP_MSGT_DT2, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100171 <<_:8, DstLocalRef:24/big, SeqSegm:16, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100172 DataLen = binary:at(Remain, DataPtr-1),
173 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
174 % build parsed list of message
175 [{dst_local_ref, DstLocalRef},{seq_segm, SeqSegm},{user_data, UserData}];
176parse_sccp_msgt(?SCCP_MSGT_AK, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100177 <<_:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100178 [{dst_local_ref, DstLocalRef},{rx_seq_nr, RxSeqnr},{credit, Credit}];
179parse_sccp_msgt(?SCCP_MSGT_UDT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200180 <<_:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100181 % variable part
182 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
183 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100184 CalledPartyDec = parse_sccp_addr(CalledParty),
Harald Welte033cef02010-12-19 22:47:14 +0100185 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
186 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100187 CallingPartyDec = parse_sccp_addr(CallingParty),
Harald Welte033cef02010-12-19 22:47:14 +0100188 DataLen = binary:at(Remain, DataPtr-1),
189 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
Harald Welte11565772011-04-15 10:37:57 +0200190 [{protocol_class, {ProtoClass, PCOpt}},{called_party_addr, CalledPartyDec},
Harald Welte234c9562011-02-03 13:51:12 +0100191 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100192parse_sccp_msgt(?SCCP_MSGT_UDTS, DataBin) ->
Harald Welte030f1092011-03-11 19:08:07 +0100193 <<_:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary >> = DataBin,
194 % variable part
195 CalledPartyLen = binary:at(Remain, CalledPartyPtr-3),
196 CalledParty = binary:part(Remain, CalledPartyPtr-3+1, CalledPartyLen),
197 CalledPartyDec = parse_sccp_addr(CalledParty),
198 CallingPartyLen = binary:at(Remain, CallingPartyPtr-2),
199 CallingParty = binary:part(Remain, CallingPartyPtr-2+1, CallingPartyLen),
200 CallingPartyDec = parse_sccp_addr(CallingParty),
201 DataLen = binary:at(Remain, DataPtr-1),
202 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
203 [{return_cause, ReturnCause},{called_party_addr, CalledPartyDec},
204 {calling_party_addr, CallingPartyDec},{user_data, UserData}];
Harald Welte033cef02010-12-19 22:47:14 +0100205parse_sccp_msgt(?SCCP_MSGT_ED, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100206 <<_:8, DstLocalRef:24/big, DataPtr:8, Remain/binary>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100207 DataLen = binary:at(Remain, DataPtr-1),
208 UserData = binary:part(Remain, DataPtr-1+1, DataLen),
209 [{dst_local_ref, DstLocalRef}, {user_data, UserData}];
210parse_sccp_msgt(?SCCP_MSGT_EA, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100211 <<_:8, DstLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100212 [{dst_local_ref, DstLocalRef}];
213parse_sccp_msgt(?SCCP_MSGT_RSR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100214 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100215 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},{reset_cause, ResetCause}];
216parse_sccp_msgt(?SCCP_MSGT_RSC, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100217 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100218 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef}];
219parse_sccp_msgt(?SCCP_MSGT_ERR, DataBin) ->
Harald Welte56ee7a62010-12-20 13:34:32 +0100220 <<_:8, DstLocalRef:24/big, ErrCause:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100221 [{dst_local_ref, DstLocalRef},{error_cause, ErrCause}];
222parse_sccp_msgt(?SCCP_MSGT_IT, DataBin) ->
Harald Welte11565772011-04-15 10:37:57 +0200223 <<_:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt: 4, ProtoClass:4, SegmSeq:16, Credit:8>> = DataBin,
Harald Welte033cef02010-12-19 22:47:14 +0100224 [{dst_local_ref, DstLocalRef},{src_local_ref, SrcLocalRef},
Harald Welte11565772011-04-15 10:37:57 +0200225 {protocol_class, {ProtoClass, PCOpt}},{seq_segm, SegmSeq},{credit, Credit}].
Harald Welte033cef02010-12-19 22:47:14 +0100226% FIXME: XUDT/XUDTS, LUDT/LUDTS
227
228% process one incoming SCCP message
229parse_sccp_msg(DataBin) ->
230 MsgType = binary:first(DataBin),
231 Parsed = parse_sccp_msgt(MsgType, DataBin),
232 {ok, #sccp_msg{msg_type = MsgType, parameters = Parsed}}.
233
234% Encoding Part
235
Harald Welte0e1709c2011-02-06 22:17:53 +0100236gt_enc_by_odd(Odd) ->
237 if Odd == 1 ->
238 1;
239 true ->
240 2
241 end.
242
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200243encode_gt(undefined) ->
244 {?SCCP_GTI_NO_GT, <<>>};
Harald Welte234c9562011-02-03 13:51:12 +0100245encode_gt(#global_title{gti = GTind, phone_number = PhoneNum,
246 nature_of_addr_ind = Nature,
Harald Welte0e1709c2011-02-06 22:17:53 +0100247 trans_type = TransType, encoding = _EncOrig,
Harald Welte234c9562011-02-03 13:51:12 +0100248 numbering_plan = NumPlan}) ->
249 case GTind of
250 ?SCCP_GTI_NO_GT ->
251 {GTind, <<>>};
252 ?SCCP_GTI_NAT_ONLY ->
253 % Figure 7/Q.713
254 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
255 {GTind, <<OddEven:1, Nature:7, PhoneBin/binary>>};
256 ?SCCP_GTI_TT_ONLY ->
257 % Figure 9/Q.913
258 % Used in national interfaces only, we cannot parse Digits
259 {GTind, <<TransType:8, PhoneNum/binary>>};
260 ?SCCP_GTI_TT_NP_ENC ->
261 % Figure 10/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100262 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
263 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100264 {GTind, <<TransType:8, NumPlan:4, Enc:4, PhoneBin/binary>>};
265 ?SCCP_GTI_TT_NP_ENC_NAT ->
266 % Figure 11/Q.713
Harald Welte0e1709c2011-02-06 22:17:53 +0100267 {PhoneBin, OddEven} = isup_codec:encode_isup_party(PhoneNum),
268 Enc = gt_enc_by_odd(OddEven),
Harald Welte234c9562011-02-03 13:51:12 +0100269 {GTind, <<TransType:8, NumPlan:4, Enc:4, 0:1, Nature:7, PhoneBin/binary>>}
270 end.
271
272encode_pc(PointCode) ->
273 case PointCode of
274 undef ->
275 {0, <<>>};
276 _ ->
Harald Welte9c3b1bb2011-10-12 17:00:34 +0200277 {1, <<PointCode:16/little>>}
Harald Welte234c9562011-02-03 13:51:12 +0100278 end.
279
280encode_ssn(SSN) ->
281 case SSN of
282 undef ->
283 {0, <<>>};
284 _ ->
285 {1, <<SSN:8>>}
286 end.
287
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200288undef_or_true(Foo) ->
289 case Foo of
290 undefined -> 0;
291 0 -> 0;
292 _ -> 1
293 end.
294
295
Harald Welte234c9562011-02-03 13:51:12 +0100296encode_sccp_addr(#sccp_addr{res_nat_use = ResNatUse,
297 route_on_ssn = RoutInd,
298 point_code = PointCode,
299 ssn = SSN,
300 global_title = GT}) ->
301
302 {GTind, GTbin} = encode_gt(GT),
303 {SSNind, SSNbin} = encode_ssn(SSN),
304 {PCind, PCbin} = encode_pc(PointCode),
Harald Welte5a1cf3c2011-04-14 21:55:13 +0200305 ResNatOut = undef_or_true(ResNatUse),
306 RoutIndOut = undef_or_true(RoutInd),
307 <<ResNatOut:1, RoutIndOut:1, GTind:4, SSNind:1, PCind:1, PCbin/binary, SSNbin/binary, GTbin/binary>>.
Harald Welte234c9562011-02-03 13:51:12 +0100308
309
Harald Welte033cef02010-12-19 22:47:14 +0100310encode_sccp_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
311 DataBinLen8 = DataBinLen*8,
312 <<OptNum:8, DataBinLen:8, DataBin:DataBinLen8>>;
313encode_sccp_opt({OptAtom,_}) when is_atom(OptAtom) ->
314 <<>>.
315
316encode_sccp_opts([], OptEnc) ->
317 % end of options + convert to binary
318 list_to_binary([OptEnc, ?SCCP_PNC_END_OF_OPTIONAL]);
319encode_sccp_opts([CurOpt|OptPropList], OptEnc) ->
320 CurOptEnc = encode_sccp_opt(CurOpt),
321 encode_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
322
323
324
325encode_sccp_msgt(?SCCP_MSGT_CR, Params) ->
326 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200327 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100328 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200329 <<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100330encode_sccp_msgt(?SCCP_MSGT_CC, Params) ->
331 SrcLocalRef = proplists:get_value(src_local_ref, Params),
332 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200333 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte033cef02010-12-19 22:47:14 +0100334 OptBin = encode_sccp_opts(Params, []),
Harald Welte11565772011-04-15 10:37:57 +0200335 <<?SCCP_MSGT_CC:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100336encode_sccp_msgt(?SCCP_MSGT_CREF, Params) ->
337 DstLocalRef = proplists:get_value(dst_local_ref, Params),
338 RefusalCause = proplists:get_value(refusal_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100339 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100340 <<?SCCP_MSGT_CREF:8, DstLocalRef:24/big, RefusalCause:8, OptBin/binary>>;
Harald Welte033cef02010-12-19 22:47:14 +0100341encode_sccp_msgt(?SCCP_MSGT_RLSD, Params) ->
342 SrcLocalRef = proplists:get_value(src_local_ref, Params),
343 DstLocalRef = proplists:get_value(dst_local_ref, Params),
344 ReleaseCause = proplists:get_value(release_cause, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100345 OptBin = encode_sccp_opts(Params, []),
Harald Welte56ee7a62010-12-20 13:34:32 +0100346 <<?SCCP_MSGT_RLSD:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, OptBin/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100347encode_sccp_msgt(?SCCP_MSGT_RLC, Params) ->
348 SrcLocalRef = proplists:get_value(src_local_ref, Params),
349 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100350 <<?SCCP_MSGT_RLC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100351encode_sccp_msgt(?SCCP_MSGT_DT1, Params) ->
352 DstLocalRef = proplists:get_value(dst_local_ref, Params),
353 SegmReass = proplists:get_value(segm_reass, Params),
354 UserData = proplists:get_value(user_data, Params),
355 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100356 <<?SCCP_MSGT_DT1:8, DstLocalRef:24/big, SegmReass:8, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100357encode_sccp_msgt(?SCCP_MSGT_DT2, Params) ->
358 DstLocalRef = proplists:get_value(dst_local_ref, Params),
359 SeqSegm = proplists:get_value(seq_segm, Params),
360 UserData = proplists:get_value(user_data, Params),
361 UserDataLen = byte_size(UserData),
Harald Welte56ee7a62010-12-20 13:34:32 +0100362 <<?SCCP_MSGT_DT2:8, DstLocalRef:24/big, SeqSegm:16, 1:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100363encode_sccp_msgt(?SCCP_MSGT_AK, Params) ->
364 DstLocalRef = proplists:get_value(dst_local_ref, Params),
365 RxSeqnr = proplists:get_value(rx_seqnr, Params),
366 Credit = proplists:get_value(credit, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100367 <<?SCCP_MSGT_AK:8, DstLocalRef:24/big, RxSeqnr:8, Credit:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100368encode_sccp_msgt(?SCCP_MSGT_UDT, Params) ->
Harald Welte11565772011-04-15 10:37:57 +0200369 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100370 CalledParty = proplists:get_value(called_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100371 CalledPartyEnc = encode_sccp_addr(CalledParty),
372 CalledPartyLen = byte_size(CalledPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100373 CallingParty = proplists:get_value(calling_party_addr, Params),
Harald Welte234c9562011-02-03 13:51:12 +0100374 CallingPartyEnc = encode_sccp_addr(CallingParty),
375 CallingPartyLen = byte_size(CallingPartyEnc),
Harald Weltec0696b02010-12-20 00:09:37 +0100376 UserData = proplists:get_value(user_data, Params),
377 UserDataLen = byte_size(UserData),
378 % variable part
379 CalledPartyPtr = 3,
380 CallingPartyPtr = 2 + (1 + CalledPartyLen),
381 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
Harald Welte234c9562011-02-03 13:51:12 +0100382 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
383 CallingPartyLen:8, CallingPartyEnc/binary,
Harald Weltec0696b02010-12-20 00:09:37 +0100384 UserDataLen:8, UserData/binary>>,
Harald Welte11565772011-04-15 10:37:57 +0200385 <<?SCCP_MSGT_UDT:8, PCOpt:4, ProtoClass:4, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Welte030f1092011-03-11 19:08:07 +0100386encode_sccp_msgt(?SCCP_MSGT_UDTS, Params) ->
387 ReturnCause = proplists:get_value(return_cause, Params),
388 CalledParty = proplists:get_value(called_party_addr, Params),
389 CalledPartyEnc = encode_sccp_addr(CalledParty),
390 CalledPartyLen = byte_size(CalledPartyEnc),
391 CallingParty = proplists:get_value(calling_party_addr, Params),
392 CallingPartyEnc = encode_sccp_addr(CallingParty),
393 CallingPartyLen = byte_size(CallingPartyEnc),
394 UserData = proplists:get_value(user_data, Params),
395 UserDataLen = byte_size(UserData),
396 % variable part
397 CalledPartyPtr = 3,
398 CallingPartyPtr = 2 + (1 + CalledPartyLen),
399 DataPtr = 1 + (1 + CalledPartyLen) + (1 + CallingPartyLen),
400 Remain = <<CalledPartyLen:8, CalledPartyEnc/binary,
401 CallingPartyLen:8, CallingPartyEnc/binary,
402 UserDataLen:8, UserData/binary>>,
403 <<?SCCP_MSGT_UDTS:8, ReturnCause:8, CalledPartyPtr:8, CallingPartyPtr:8, DataPtr:8, Remain/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100404encode_sccp_msgt(?SCCP_MSGT_ED, Params) ->
405 DstLocalRef = proplists:get_value(dst_local_ref, Params),
406 UserData = proplists:get_value(user_data, Params),
407 UserDataLen = byte_size(UserData),
408 DataPtr = 1,
Harald Welte56ee7a62010-12-20 13:34:32 +0100409 <<?SCCP_MSGT_ED:8, DstLocalRef:24/big, DataPtr:8, UserDataLen:8, UserData/binary>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100410encode_sccp_msgt(?SCCP_MSGT_EA, Params) ->
411 DstLocalRef = proplists:get_value(dst_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100412 <<?SCCP_MSGT_EA:8, DstLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100413encode_sccp_msgt(?SCCP_MSGT_RSR, Params) ->
414 DstLocalRef = proplists:get_value(dst_local_ref, Params),
415 SrcLocalRef = proplists:get_value(src_local_ref, Params),
416 ResetCause = proplists:get_value(reset_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100417 <<?SCCP_MSGT_RSR:8, DstLocalRef:24/big, SrcLocalRef:24/big, ResetCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100418encode_sccp_msgt(?SCCP_MSGT_RSC, Params) ->
419 DstLocalRef = proplists:get_value(dst_local_ref, Params),
420 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100421 <<?SCCP_MSGT_RSC:8, DstLocalRef:24/big, SrcLocalRef:24/big>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100422encode_sccp_msgt(?SCCP_MSGT_ERR, Params) ->
423 DstLocalRef = proplists:get_value(dst_local_ref, Params),
424 ErrCause = proplists:get_value(error_cause, Params),
Harald Welte56ee7a62010-12-20 13:34:32 +0100425 <<?SCCP_MSGT_ERR:8, DstLocalRef:24/big, ErrCause:8>>;
Harald Weltec0696b02010-12-20 00:09:37 +0100426encode_sccp_msgt(?SCCP_MSGT_IT, Params) ->
427 DstLocalRef = proplists:get_value(dst_local_ref, Params),
428 SrcLocalRef = proplists:get_value(src_local_ref, Params),
Harald Welte11565772011-04-15 10:37:57 +0200429 {ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
Harald Welte09b43992010-12-20 12:21:03 +0100430 SegmSeq = proplists:get_value(seq_segm, Params),
Harald Weltec0696b02010-12-20 00:09:37 +0100431 Credit = proplists:get_value(credit, Params),
Harald Welte11565772011-04-15 10:37:57 +0200432 <<?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 +0100433% FIXME: XUDT/XUDTS, LUDT/LUDTS
434
Harald Welte033cef02010-12-19 22:47:14 +0100435
436% encode one sccp message data structure into the on-wire format
437encode_sccp_msg(#sccp_msg{msg_type = MsgType, parameters = Params}) ->
438 encode_sccp_msgt(MsgType, Params).
Harald Welte9abbbad2011-04-21 12:19:41 +0200439
440% is the supplied message type a connectionless message?
441is_connectionless(#sccp_msg{msg_type = MsgType}) ->
442 is_connectionless(MsgType);
443is_connectionless(MsgType) ->
444 case MsgType of
445 ?SCCP_MSGT_UDT -> true;
446 ?SCCP_MSGT_UDTS -> true;
447 ?SCCP_MSGT_XUDT -> true;
448 ?SCCP_MSGT_XUDTS -> true;
449 ?SCCP_MSGT_LUDT -> true;
450 ?SCCP_MSGT_LUDTS -> true;
451 _ -> false
452 end.
Harald Welte9baab6d2011-12-08 00:46:00 +0100453
454
455gen_gt_helper(Number) when is_list(Number) ->
456 #global_title{gti=?SCCP_GTI_NAT_ONLY,
457 nature_of_addr_ind=?SCCP_NAI_INTERNATIONAL,
458 phone_number = Number}.
459
460gen_addr_helper(Gt, Pc, Ssn) when is_record(Gt, global_title) ->
461 #sccp_addr{point_code=Pc, ssn=Ssn, global_title=Gt};
462gen_addr_helper(Number, Pc, Ssn) when is_list(Number) ->
463 Gt = gen_gt_helper(Number),
464 gen_addr_helper(Gt, Pc, Ssn).
465
466
467gen_addr_helper(Gt, Pc) when is_record(Gt, global_title) ->
468 #sccp_addr{point_code=Pc, global_title=Gt};
469gen_addr_helper(Number, Pc) when is_list(Number) ->
470 Gt = gen_gt_helper(Number),
471 gen_addr_helper(Gt, Pc).