blob: 523a0e5fea4623404a536b604379378c0885e92d [file] [log] [blame]
Harald Welte50a44c22011-01-15 21:39:20 +01001% ITU-T Q.76x ISUPcoding / decoding
2
3% (C) 2011 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(isup_codec).
21-author('Harald Welte <laforge@gnumonks.org>').
22-include("isup.hrl").
23
24-export([parse_isup_msg/1, encode_isup_msg/1]).
25
Harald Welte01f8ea32011-01-17 21:30:42 +010026-compile(export_all).
27
Harald Weltede30a872011-01-16 17:12:56 +010028parse_isup_party(<<>>, OddEven, DigitList) ->
29 % in case of odd number of digits, we need to cut the last
30 case OddEven of
31 1 ->
Harald Welte01f8ea32011-01-17 21:30:42 +010032 lists:sublist(DigitList, length(DigitList)-1);
Harald Weltede30a872011-01-16 17:12:56 +010033 0 ->
34 DigitList
35 end;
36parse_isup_party(BcdBin, OddEven, DigitList) ->
37 <<Second:4, First:4, Remain/binary>> = BcdBin,
38 NewDigits = [First, Second],
39 parse_isup_party(Remain, OddEven, DigitList ++ NewDigits).
40
41parse_isup_party(BinBcd, OddEven) when is_binary(BinBcd) ->
42 parse_isup_party(BinBcd, OddEven, []).
43
44
45% parse a single option
Harald Welte01f8ea32011-01-17 21:30:42 +010046parse_isup_opt(OptType = ?ISUP_PAR_CALLED_P_NUM, _OptLen, Content) ->
Harald Weltede30a872011-01-16 17:12:56 +010047 % C.3.7 Called Party Number
48 <<OddEven:1, Nature:7, Inn:1, NumPlan:3, 0:4, Remain/binary>> = Content,
49 PhoneNum = parse_isup_party(Remain, OddEven),
50 {OptType, #party_number{nature_of_addr_ind = Nature,
51 internal_net_num = Inn,
52 numbering_plan = NumPlan,
53 phone_number = PhoneNum}};
Harald Welte01f8ea32011-01-17 21:30:42 +010054parse_isup_opt(OptType = ?ISUP_PAR_CALLING_P_NUM, _OptLen, Content) ->
Harald Weltede30a872011-01-16 17:12:56 +010055 % C.3.8 Calling Party Number
56 <<OddEven:1, Nature:7, Ni:1, NumPlan:3, PresRestr:2, Screen:2, Remain/binary>> = Content,
57 PhoneNum = parse_isup_party(Remain, OddEven),
58 {OptType, #party_number{nature_of_addr_ind = Nature,
59 number_incompl_ind = Ni,
60 numbering_plan = NumPlan,
61 present_restrict = PresRestr,
62 screening_ind = Screen,
63 phone_number = PhoneNum}};
Harald Welte01f8ea32011-01-17 21:30:42 +010064parse_isup_opt(OptType = ?ISUP_PAR_CONNECTED_NUM, _OptLen, Content) ->
Harald Weltede30a872011-01-16 17:12:56 +010065 % C.3.14 Connected Number
66 <<OddEven:1, Nature:7, 0:1, NumPlan:3, PresRestr:2, Screen:2, Remain/binary>> = Content,
67 PhoneNum = parse_isup_party(Remain, OddEven),
68 {OptType, #party_number{nature_of_addr_ind = Nature,
69 numbering_plan = NumPlan,
70 present_restrict = PresRestr,
71 screening_ind = Screen,
72 phone_number = PhoneNum}};
Harald Welte01f8ea32011-01-17 21:30:42 +010073parse_isup_opt(OptType = ?ISUP_PAR_SUBSEQ_NUM, _OptLen, Content) ->
Harald Weltede30a872011-01-16 17:12:56 +010074 % C.3.32 Subsequent Number
Harald Welte01f8ea32011-01-17 21:30:42 +010075 <<OddEven:1, 0:7, Remain/binary>> = Content,
Harald Weltede30a872011-01-16 17:12:56 +010076 PhoneNum = parse_isup_party(Remain, OddEven),
77 {OptType, #party_number{phone_number = PhoneNum}};
78parse_isup_opt(OptType, OptLen, Content) ->
79 {OptType, {OptLen, Content}}.
80
81% parse a Binary into a list of options
82parse_isup_opts(<<>>, OptList) ->
83 % empty list
84 OptList;
85parse_isup_opts(<<0>>, OptList) ->
86 % end of options
87 OptList;
88parse_isup_opts(OptBin, OptList) when is_binary(OptBin) ->
89 <<OptType:8, OptLen:8, Content:OptLen/binary, Remain/binary>> = OptBin,
90 NewOpt = parse_isup_opt(OptType, OptLen, Content),
Harald Welte01f8ea32011-01-17 21:30:42 +010091 parse_isup_opts(Remain, OptList ++ [NewOpt]).
92parse_isup_opts(OptBin) ->
93 parse_isup_opts(OptBin, []).
Harald Weltede30a872011-01-16 17:12:56 +010094
Harald Welte50a44c22011-01-15 21:39:20 +010095% References to 'Tabe C-xxx' are to Annex C of Q.767
96
97% Default case: no fixed and no variable parts, only options
98% ANM, RLC, FOT
99parse_isup_msgt(M, Bin) when
100 M == ?ISUP_MSGT_ANM;
101 M == ?ISUP_MSGT_RLC;
Harald Weltede30a872011-01-16 17:12:56 +0100102 M == ?ISUP_MSGT_FOT ->
Harald Welte50a44c22011-01-15 21:39:20 +0100103 parse_isup_opts(Bin);
104% Table C-5 Address complete
105parse_isup_msgt(?ISUP_MSGT_ACM, Bin) ->
106 <<BackCallInd:16, Remain/binary>> = Bin,
107 BciOpt = {backward_call_ind, BackCallInd},
Harald Weltede30a872011-01-16 17:12:56 +0100108 Opts = parse_isup_opts(Remain),
Harald Welte50a44c22011-01-15 21:39:20 +0100109 [BciOpt|Opts];
110% Table C-7 Call progress
111parse_isup_msgt(?ISUP_MSGT_CPG, Bin) ->
112 <<EventInf:8, Remain/binary>> = Bin,
113 BciOpt = {event_info, EventInf},
Harald Weltede30a872011-01-16 17:12:56 +0100114 Opts = parse_isup_opts(Remain),
Harald Welte50a44c22011-01-15 21:39:20 +0100115 [BciOpt|Opts];
116% Table C-9 Circuit group reset acknowledgement
117parse_isup_msgt(?ISUP_MSGT_GRA, Bin) ->
118 % V: Range and status
Harald Welte01f8ea32011-01-17 21:30:42 +0100119 <<PtrVar:8, Remain/binary>> = Bin,
120 RangStsLen = binary:at(Remain, PtrVar),
121 RangeStatus = binary:part(Remain, PtrVar+1, RangStsLen),
122 RangeStsTuple = {?ISUP_PAR_RANGE_AND_STATUS, {RangStsLen, RangeStatus}},
123 [RangeStsTuple];
Harald Welte50a44c22011-01-15 21:39:20 +0100124% Table C-11 Connect
125parse_isup_msgt(?ISUP_MSGT_CON, Bin) ->
126 <<BackCallInd:16, Remain/binary>> = Bin,
127 BciOpt = {backward_call_ind, BackCallInd},
Harald Weltede30a872011-01-16 17:12:56 +0100128 Opts = parse_isup_opts(Remain),
Harald Welte50a44c22011-01-15 21:39:20 +0100129 [BciOpt|Opts];
130% Table C-12 Continuity
131parse_isup_msgt(?ISUP_MSGT_COT, Bin) ->
132 <<ContInd:8>> = Bin,
133 [{continuity_ind, ContInd}];
134% Table C-16 Initial address
135parse_isup_msgt(?ISUP_MSGT_IAM, Bin) ->
136 <<CINat:8, FwCallInd:16/big, CallingCat:8, TransmReq:8, VarAndOpt/binary>> = Bin,
Harald Welte01f8ea32011-01-17 21:30:42 +0100137 %<<CINat:8, FwCallInd:16/big, CallingCat:8, TransmReq:8, PtrVar:8, PtrOpt:8, VarAndOpt/binary>> = Bin,
Harald Welte50a44c22011-01-15 21:39:20 +0100138 FixedOpts = [{conn_ind_nature, CINat}, {fw_call_ind, FwCallInd}, {calling_cat, CallingCat},
139 {transm_medium_req, TransmReq}],
Harald Welte01f8ea32011-01-17 21:30:42 +0100140 <<PtrVar:8, PtrOpt:8, _/binary>> = VarAndOpt,
Harald Welte50a44c22011-01-15 21:39:20 +0100141 % V: Called Party Number
Harald Welte01f8ea32011-01-17 21:30:42 +0100142 CalledPartyLen = binary:at(VarAndOpt, PtrVar),
143 CalledParty = binary:part(VarAndOpt, PtrVar+1, CalledPartyLen),
144 VarOpts = [parse_isup_opt(?ISUP_PAR_CALLED_P_NUM, CalledPartyLen, CalledParty)],
145 % Optional part
146 Remain = binary:part(VarAndOpt, 1 + PtrOpt, byte_size(VarAndOpt)-(1+PtrOpt)),
Harald Welte50a44c22011-01-15 21:39:20 +0100147 Opts = parse_isup_opts(Remain),
Harald Welte01f8ea32011-01-17 21:30:42 +0100148 FixedOpts ++ VarOpts ++ Opts;
Harald Welte50a44c22011-01-15 21:39:20 +0100149% Table C-17 Release
150parse_isup_msgt(?ISUP_MSGT_REL, Bin) ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100151 <<PtrVar:8, PtrOpt:8, VarAndOpt/binary>> = Bin,
Harald Welte50a44c22011-01-15 21:39:20 +0100152 % V: Cause indicators
Harald Welte01f8ea32011-01-17 21:30:42 +0100153 CauseIndLen = binary:at(VarAndOpt, PtrVar),
154 CauseInd = binary:part(VarAndOpt, PtrVar+1, CauseIndLen),
155 VarOpts = {?ISUP_PAR_CAUSE_IND, {CauseIndLen, CauseInd}},
156 Remain = binary:part(VarAndOpt, 1 + PtrOpt, byte_size(VarAndOpt)-(1+PtrOpt)),
Harald Welte50a44c22011-01-15 21:39:20 +0100157 Opts = parse_isup_opts(Remain),
Harald Welte01f8ea32011-01-17 21:30:42 +0100158 VarOpts ++ Opts;
Harald Welte50a44c22011-01-15 21:39:20 +0100159% Table C-19 Subsequent address
160parse_isup_msgt(?ISUP_MSGT_SAM, Bin) ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100161 <<PtrVar:8, PtrOpt:8, VarAndOpt/binary>> = Bin,
Harald Welte50a44c22011-01-15 21:39:20 +0100162 % V: Subsequent number
Harald Welte01f8ea32011-01-17 21:30:42 +0100163 SubseqNumLen = binary:at(VarAndOpt, PtrVar),
164 SubsetNum = binary:part(VarAndOpt, PtrVar+1, SubseqNumLen),
165 VarOpts = [{?ISUP_PAR_SUBSEQ_NUM, {SubseqNumLen, SubsetNum}}],
166 Remain = binary:part(VarAndOpt, 1 + PtrOpt, byte_size(VarAndOpt)-(1+PtrOpt)),
Harald Welte50a44c22011-01-15 21:39:20 +0100167 Opts = parse_isup_opts(Remain),
Harald Welte01f8ea32011-01-17 21:30:42 +0100168 VarOpts ++ Opts;
Harald Welte50a44c22011-01-15 21:39:20 +0100169% Table C-21 Suspend, Resume
Harald Weltede30a872011-01-16 17:12:56 +0100170parse_isup_msgt(Msgt, Bin) when Msgt == ?ISUP_MSGT_RES; Msgt == ?ISUP_MSGT_SUS ->
Harald Welte50a44c22011-01-15 21:39:20 +0100171 <<SuspResInd:8, Remain/binary>> = Bin,
172 FixedOpts = [{susp_res_ind, SuspResInd}],
173 Opts = parse_isup_opts(Remain),
174 [FixedOpts|Opts];
175% Table C-23
176parse_isup_msgt(M, <<>>) when
177 M == ?ISUP_MSGT_BLO;
178 M == ?ISUP_MSGT_BLA;
179 M == ?ISUP_MSGT_CCR;
180 M == ?ISUP_MSGT_RSC;
181 M == ?ISUP_MSGT_UBL;
182 M == ?ISUP_MSGT_UBA ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100183 [];
Harald Welte50a44c22011-01-15 21:39:20 +0100184% Table C-25
185parse_isup_msgt(M, Bin) when
186 M == ?ISUP_MSGT_CGB;
187 M == ?ISUP_MSGT_CGBA;
Harald Welte01f8ea32011-01-17 21:30:42 +0100188 M == ?ISUP_MSGT_CGU;
189 M == ?ISUP_MSGT_CGUA ->
190 <<CGMsgt:8, PtrVar:8, VarBin/binary>> = Bin,
Harald Welte50a44c22011-01-15 21:39:20 +0100191 FixedOpts = [{cg_supv_msgt, CGMsgt}],
192 % V: Range and status
Harald Welte01f8ea32011-01-17 21:30:42 +0100193 RangStsLen = binary:at(VarBin, PtrVar),
194 RangeStatus = binary:part(VarBin, PtrVar+1, RangStsLen),
195 VarOpts = [{?ISUP_PAR_RANGE_AND_STATUS, {RangStsLen, RangeStatus}}],
196 FixedOpts ++ VarOpts;
Harald Welte50a44c22011-01-15 21:39:20 +0100197% Table C-26 Circuit group reset
198parse_isup_msgt(?ISUP_MSGT_GRS, Bin) ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100199 <<PtrVar:8, VarBin/binary>> = Bin,
Harald Welte50a44c22011-01-15 21:39:20 +0100200 % V: Range without status
Harald Welte01f8ea32011-01-17 21:30:42 +0100201 RangeLen = binary:at(VarBin, PtrVar),
202 Range = binary:part(VarBin, PtrVar+1, RangeLen),
203 [{?ISUP_PAR_RANGE_AND_STATUS, {RangeLen, Range}}].
Harald Welte50a44c22011-01-15 21:39:20 +0100204
205
Harald Welte01f8ea32011-01-17 21:30:42 +0100206parse_isup_msg(DataBin) when is_binary(DataBin) ->
207 <<Cic:12/little, 0:4, MsgType:8, Remain/binary>> = DataBin,
Harald Welte50a44c22011-01-15 21:39:20 +0100208 Opts = parse_isup_msgt(MsgType, Remain),
209 #isup_msg{cic = Cic, msg_type = MsgType, parameters = Opts}.
Harald Weltede30a872011-01-16 17:12:56 +0100210
211
Harald Welte01f8ea32011-01-17 21:30:42 +0100212% encode a phone number from a list of digits into the BCD binary sequence
Harald Weltede30a872011-01-16 17:12:56 +0100213encode_isup_party(BcdList) ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100214 encode_isup_party(BcdList, <<>>, length(BcdList)).
Harald Weltede30a872011-01-16 17:12:56 +0100215encode_isup_party([], Bin, NumDigits) ->
216 case NumDigits rem 2 of
217 1 ->
218 {Bin, 1};
219 0 ->
220 {Bin, 0}
221 end;
222encode_isup_party([First,Second|BcdList], Bin, NumDigits) ->
Harald Welte01f8ea32011-01-17 21:30:42 +0100223 encode_isup_party(BcdList, <<Bin/binary, Second:4, First:4>>, NumDigits).
224
Harald Weltede30a872011-01-16 17:12:56 +0100225% encode a single option
226encode_isup_opt(?ISUP_PAR_CALLED_P_NUM,
227 #party_number{nature_of_addr_ind = Nature,
228 internal_net_num = Inn,
229 numbering_plan = NumPlan,
230 phone_number= PhoneNum}) ->
231 % C.3.7 Called Party Number
232 {PhoneBin, OddEven} = encode_isup_party(PhoneNum),
Harald Welte01f8ea32011-01-17 21:30:42 +0100233 <<OddEven:1, Nature:7, Inn:1, NumPlan:3, 0:4, PhoneBin/binary>>;
Harald Weltede30a872011-01-16 17:12:56 +0100234encode_isup_opt(?ISUP_PAR_CALLING_P_NUM,
235 #party_number{nature_of_addr_ind = Nature,
236 number_incompl_ind = Ni,
237 numbering_plan = NumPlan,
238 present_restrict = PresRestr,
239 screening_ind = Screen,
240 phone_number= PhoneNum}) ->
241 % C.3.8 Calling Party Number
242 {PhoneBin, OddEven} = encode_isup_party(PhoneNum),
243 <<OddEven:1, Nature:7, Ni:1, NumPlan:3, PresRestr:2, Screen:2, PhoneBin/binary>>;
244encode_isup_opt(?ISUP_PAR_CONNECTED_NUM,
245 #party_number{nature_of_addr_ind = Nature,
246 numbering_plan = NumPlan,
247 present_restrict = PresRestr,
248 screening_ind = Screen,
249 phone_number = PhoneNum}) ->
250 % C.3.14 Connected Number
251 {PhoneBin, OddEven} = encode_isup_party(PhoneNum),
252 <<OddEven:1, Nature:7, 0:1, NumPlan:3, PresRestr:2, Screen:2, PhoneBin/binary>>;
253encode_isup_opt(OptNum, {OptLen, Binary}) when is_binary(Binary) ->
254 Binary.
255
Harald Welte01f8ea32011-01-17 21:30:42 +0100256encode_isup_msg(#isup_msg{}) ->
257 foo.