blob: 211253548b120714015bc0c52b41565fd0363428 [file] [log] [blame]
Harald Weltea68d96e2011-02-10 09:49:46 +01001% MAP masquerading application
2
Harald Welte7bd1d4a2013-02-06 09:02:46 +01003% (C) 2010-2013 by Harald Welte <laforge@gnumonks.org>
4% (C) 2010-2013 by On-Waves
Harald Weltea68d96e2011-02-10 09:49:46 +01005%
6% All Rights Reserved
7%
8% This program is free software; you can redistribute it and/or modify
Harald Weltefb222d92012-04-16 13:19:15 +02009% it under the terms of the GNU Affero General Public License as
10% published by the Free Software Foundation; either version 3 of the
11% License, or (at your option) any later version.
Harald Weltea68d96e2011-02-10 09:49:46 +010012%
13% This program is distributed in the hope that it will be useful,
14% but WITHOUT ANY WARRANTY; without even the implied warranty of
15% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16% GNU General Public License for more details.
17%
Harald Weltefb222d92012-04-16 13:19:15 +020018% You should have received a copy of the GNU Affero General Public License
19% along with this program. If not, see <http://www.gnu.org/licenses/>.
20%
21% Additional Permission under GNU AGPL version 3 section 7:
22%
23% If you modify this Program, or any covered work, by linking or
24% combining it with runtime libraries of Erlang/OTP as released by
25% Ericsson on http://www.erlang.org (or a modified version of these
26% libraries), containing parts covered by the terms of the Erlang Public
27% License (http://www.erlang.org/EPLICENSE), the licensors of this
28% Program grant you additional permission to convey the resulting work
29% without the need to license the runtime libraries of Erlang/OTP under
30% the GNU Affero General Public License. Corresponding Source for a
31% non-source form of such a combination shall include the source code
32% for the parts of the runtime libraries of Erlang/OTP used as well as
33% that of the covered work.
Harald Weltea68d96e2011-02-10 09:49:46 +010034
35-module(map_masq).
36-author('Harald Welte <laforge@gnumonks.org>').
37%-compile(export_all).
38
Harald Weltef9629642011-02-10 20:44:46 +010039-export([mangle_map/2, config_update/0]).
Harald Weltea68d96e2011-02-10 09:49:46 +010040
41-include_lib("osmo_map/include/map.hrl").
Harald Weltef9629642011-02-10 20:44:46 +010042-include_lib("osmo_ss7/include/isup.hrl").
43
44% Use the MAP address translation table to alter an ISDN-Address-String
Harald Welte29e589f2011-02-25 15:17:57 +010045patch_map_isdn_addr(_From, asn1_NOVALUE, _Type) ->
Harald Weltef9629642011-02-10 20:44:46 +010046 asn1_NOVALUE;
Harald Welte29e589f2011-02-25 15:17:57 +010047patch_map_isdn_addr(From, AddrIn, Type) when is_binary(AddrIn) ->
48 patch_map_isdn_addr(From, binary_to_list(AddrIn), Type);
49patch_map_isdn_addr(From, AddrIn, Type) when is_list(AddrIn) ->
Harald Weltef9629642011-02-10 20:44:46 +010050 % obtain some configuration data
Harald Weltea53a63a2012-02-13 22:10:33 +010051 {ok, Tbl} = application:get_env(mgw_nat, map_rewrite_table),
52 {ok, IntPfx} = application:get_env(mgw_nat, intern_pfx),
Harald Weltef9629642011-02-10 20:44:46 +010053 % Decode the list of octets into an party_number
54 AddrInDec = map_codec:parse_addr_string(AddrIn),
55 % First we always internationalize the address
Harald Welte6a33c1e2011-02-10 21:40:40 +010056 AddrInIntl = mgw_nat:isup_party_internationalize(AddrInDec, IntPfx),
Harald Weltef9629642011-02-10 20:44:46 +010057 % And then patch/replace the address digits
58 DigitsIn = AddrInIntl#party_number.phone_number,
Harald Welte29e589f2011-02-25 15:17:57 +010059 DigitsOut = patch_map_isdn_digits(From, DigitsIn, Type, Tbl),
Harald Weltef9629642011-02-10 20:44:46 +010060 AddrOutIntl = AddrInIntl#party_number{phone_number = DigitsOut},
61 if AddrOutIntl == AddrInDec ->
62 ok;
63 true ->
64 io:format("Translating MAP-ISDN-Addess ~p ~p -> ~p~n",
65 [Type, AddrInDec, AddrOutIntl])
66 end,
Harald Welte62aa7c62011-02-10 22:52:01 +010067 map_codec:encode_addr_string(AddrOutIntl).
Harald Weltef9629642011-02-10 20:44:46 +010068
Harald Welte29e589f2011-02-25 15:17:57 +010069patch_map_isdn_digits(_From, AddrIn, _Type, []) ->
Harald Weltef9629642011-02-10 20:44:46 +010070 AddrIn;
Harald Welte29e589f2011-02-25 15:17:57 +010071patch_map_isdn_digits(From, AddrIn, TypeIn, [Head|Tail]) ->
Harald Weltef9629642011-02-10 20:44:46 +010072 case Head of
73 {TypeIn, _,_, MscSide, StpSide} ->
74 if AddrIn == MscSide ->
75 StpSide;
76 AddrIn == StpSide ->
77 MscSide;
78 true ->
Harald Welte29e589f2011-02-25 15:17:57 +010079 patch_map_isdn_digits(From, AddrIn, TypeIn, Tail)
Harald Weltef9629642011-02-10 20:44:46 +010080 end;
81 _ ->
Harald Welte29e589f2011-02-25 15:17:57 +010082 patch_map_isdn_digits(From, AddrIn, TypeIn, Tail)
Harald Weltef9629642011-02-10 20:44:46 +010083 end.
Harald Weltea68d96e2011-02-10 09:49:46 +010084
85mangle_msisdn(from_stp, _Opcode, AddrIn) ->
Harald Weltea53a63a2012-02-13 22:10:33 +010086 {ok, IntPfx} = application:get_env(mgw_nat, intern_pfx),
Harald Welte6a33c1e2011-02-10 21:40:40 +010087 mgw_nat:isup_party_internationalize(AddrIn, IntPfx).
Harald Weltea68d96e2011-02-10 09:49:46 +010088
Harald Welte449a3172011-02-10 15:06:27 +010089% Someobdy inquires on Routing Info for a MS (from HLR)
Harald Welte29e589f2011-02-25 15:17:57 +010090patch(From = from_stp, #'SendRoutingInfoArg'{msisdn = Msisdn,'gmsc-OrGsmSCF-Address'=GmscAddr} = P) ->
Harald Weltee78474e2011-02-10 21:04:52 +010091 % First Translate the MSISDN into international
Harald Weltea68d96e2011-02-10 09:49:46 +010092 AddrInDec = map_codec:parse_addr_string(Msisdn),
93 io:format("MSISDN IN = ~p~n", [AddrInDec]),
Harald Welte29e589f2011-02-25 15:17:57 +010094 AddrOutDec = mangle_msisdn(From, 22, AddrInDec),
Harald Weltea68d96e2011-02-10 09:49:46 +010095 io:format("MSISDN OUT = ~p~n", [AddrOutDec]),
96 AddrOutBin = map_codec:encode_addr_string(AddrOutDec),
Harald Weltee78474e2011-02-10 21:04:52 +010097 % Second, try to masquerade the G-MSC
98 GmscInDec = map_codec:parse_addr_string(GmscAddr),
99 case sccp_masq:lookup_masq_addr(orig, GmscInDec#party_number.phone_number) of
100 undef ->
101 GmscOut = GmscAddr;
102 GmscOutDigits ->
103 GmscOutDec = GmscInDec#party_number{phone_number = GmscOutDigits},
104 GmscOut = map_codec:encode_addr_string(GmscOutDec)
105 end,
106 P#'SendRoutingInfoArg'{msisdn = AddrOutBin, 'gmsc-OrGsmSCF-Address' = GmscOut};
Harald Weltea68d96e2011-02-10 09:49:46 +0100107
Harald Welte22a2b032011-02-25 17:04:57 +0100108% Someobdy inquires on Routing Info for a MS (from our HLR -> STP)
109patch(from_msc, #'SendRoutingInfoArg'{'gmsc-OrGsmSCF-Address'=GmscAddr} = P) ->
110 % try to translate the G-MSC
111 GmscInDec = map_codec:parse_addr_string(GmscAddr),
112 case sccp_masq:lookup_masq_addr(rev, GmscInDec#party_number.phone_number) of
113 undef ->
114 GmscOut = GmscAddr;
115 GmscOutDigits ->
116 GmscOutDec = GmscInDec#party_number{phone_number = GmscOutDigits},
117 GmscOut = map_codec:encode_addr_string(GmscOutDec)
118 end,
119 P#'SendRoutingInfoArg'{'gmsc-OrGsmSCF-Address' = GmscOut};
120
121
Harald Welte449a3172011-02-10 15:06:27 +0100122% HLR responds with Routing Info for a MS
Harald Welte29e589f2011-02-25 15:17:57 +0100123patch(From, #'SendRoutingInfoRes'{extendedRoutingInfo = ExtRoutInfo,
Holger Hans Peter Freyther016e3062011-02-21 22:04:38 +0100124 subscriberInfo = SubscriberInfo,
Harald Welte449a3172011-02-10 15:06:27 +0100125 'vmsc-Address' = VmscAddress} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100126 VmscAddrOut = patch_map_isdn_addr(From, VmscAddress, msc),
127 P#'SendRoutingInfoRes'{extendedRoutingInfo = patch(From, ExtRoutInfo),
128 'subscriberInfo' = patch(From, SubscriberInfo),
Harald Weltef9629642011-02-10 20:44:46 +0100129 'vmsc-Address' = VmscAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100130patch(From, #'CamelRoutingInfo'{gmscCamelSubscriptionInfo = GmscCamelSI} = P) ->
131 P#'CamelRoutingInfo'{gmscCamelSubscriptionInfo = patch(From, GmscCamelSI)};
132patch(From, {camelRoutingInfo, CRI}) ->
133 {camelRoutingInfo, patch(From, CRI)};
134patch(From, {routingInfo, RI}) ->
135 {routingInfo, patch(From, RI)};
Harald Welte449a3172011-02-10 15:06:27 +0100136
Harald Weltef9629642011-02-10 20:44:46 +0100137% HLR responds to inquiring MSC indicating the current serving MSC number
Harald Welte9fe07292012-02-13 20:54:17 +0100138patch(From, #'RoutingInfoForSM-Res'{locationInfoWithLMSI = LocInf,
139 imsi = Imsi} = P) ->
140 P#'RoutingInfoForSM-Res'{locationInfoWithLMSI = patch(From, LocInf),
141 imsi = patch_imsi(sri_sm_res, From, Imsi)};
Harald Welte29e589f2011-02-25 15:17:57 +0100142patch(From, #'LocationInfoWithLMSI'{'networkNode-Number' = NetNodeNr} = P) ->
143 NetNodeNrOut = patch_map_isdn_addr(From, NetNodeNr, msc),
Harald Weltef9629642011-02-10 20:44:46 +0100144 P#'LocationInfoWithLMSI'{'networkNode-Number' = NetNodeNrOut};
145
Harald Welte7bd1d4a2013-02-06 09:02:46 +0100146% MO-ForwardSM-Arg with optional IMSI
147patch(From, #'MO-ForwardSM-Arg'{imsi = ImsiIn} = P) ->
Harald Welte04bc9f82013-02-06 09:37:00 +0100148 P#'MO-ForwardSM-Arg'{imsi = patch_imsi(mo_fw_sm_arg, From, ImsiIn)};
Harald Welte7bd1d4a2013-02-06 09:02:46 +0100149
Harald Weltedf81bdd2011-02-10 17:21:26 +0100150% patch the roaming number as it is sent from HLR to G-MSC (SRI Resp)
Harald Welte29e589f2011-02-25 15:17:57 +0100151patch(_From, {roamingNumber, RoamNumTBCD}) ->
Harald Weltedf81bdd2011-02-10 17:21:26 +0100152 RoamNumIn = map_codec:parse_addr_string(RoamNumTBCD),
153 io:format("Roaming Number IN = ~p~n", [RoamNumIn]),
Harald Weltea53a63a2012-02-13 22:10:33 +0100154 {ok, MsrnPfxStp} = application:get_env(mgw_nat, msrn_pfx_stp),
155 {ok, MsrnPfxMsc} = application:get_env(mgw_nat, msrn_pfx_msc),
Harald Welte6a33c1e2011-02-10 21:40:40 +0100156 RoamNumOut = mgw_nat:isup_party_replace_prefix(RoamNumIn, MsrnPfxMsc, MsrnPfxStp),
Harald Weltedf81bdd2011-02-10 17:21:26 +0100157 io:format("Roaming Number OUT = ~p~n", [RoamNumOut]),
158 RoamNumOutTBCD = map_codec:encode_addr_string(RoamNumOut),
159 {roamingNumber, RoamNumOutTBCD};
160
Harald Welte449a3172011-02-10 15:06:27 +0100161
Harald Weltea68d96e2011-02-10 09:49:46 +0100162% patch a UpdateGprsLocationArg and replace SGSN number and SGSN address
163% !!! TESTING ONLY !!!
Harald Welte29e589f2011-02-25 15:17:57 +0100164patch(From, #'UpdateGprsLocationArg'{'sgsn-Number' = SgsnNum,
Harald Weltef9629642011-02-10 20:44:46 +0100165 'sgsn-Address' = SgsnAddr} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100166 SgsnNumOut = patch_map_isdn_addr(From, SgsnNum, sgsn),
Harald Weltef9629642011-02-10 20:44:46 +0100167 P#'UpdateGprsLocationArg'{'sgsn-Number'= SgsnNumOut,
168 'sgsn-Address' = SgsnAddr};
Harald Weltea68d96e2011-02-10 09:49:46 +0100169
170% Some other SGSN is sendingu us a GPRS location update. In the response,
171% we indicate teh HLR number, which we need to masquerade
Harald Welte29e589f2011-02-25 15:17:57 +0100172patch(From, #'UpdateGprsLocationRes'{'hlr-Number' = HlrNum} = P) ->
173 HlrNumOut = patch_map_isdn_addr(From, HlrNum, hlr),
Harald Weltef9629642011-02-10 20:44:46 +0100174 P#'UpdateGprsLocationRes'{'hlr-Number' = HlrNumOut};
Harald Weltea68d96e2011-02-10 09:49:46 +0100175
176% Some other MSC/VLR is sendingu us a GSM location update. In the response,
177% we indicate teh HLR number, which we need to masquerade
Harald Welte29e589f2011-02-25 15:17:57 +0100178patch(From, #'UpdateLocationRes'{'hlr-Number' = HlrNum} = P) ->
179 HlrNumOut = patch_map_isdn_addr(From, HlrNum, hlr),
Harald Weltef9629642011-02-10 20:44:46 +0100180 P#'UpdateLocationRes'{'hlr-Number' = HlrNumOut};
Harald Weltea68d96e2011-02-10 09:49:46 +0100181
182% HLR responds to VLR's MAP_RESTORE_REQ (i.e. it has lost information)
Harald Welte29e589f2011-02-25 15:17:57 +0100183patch(From, #'RestoreDataRes'{'hlr-Number' = HlrNum} = P) ->
184 HlrNumOut = patch_map_isdn_addr(From, HlrNum, hlr),
Harald Weltef9629642011-02-10 20:44:46 +0100185 P#'RestoreDataRes'{'hlr-Number' = HlrNumOut};
Harald Weltea68d96e2011-02-10 09:49:46 +0100186
187% HLR sends subscriber data to VLR/SGSN, including CAMEL info
Harald Welte29e589f2011-02-25 15:17:57 +0100188patch(From, #'InsertSubscriberDataArg'{'vlrCamelSubscriptionInfo'=VlrCamel,
Harald Weltea68d96e2011-02-10 09:49:46 +0100189 'sgsn-CAMEL-SubscriptionInfo'=SgsnCamel} = Arg) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100190 Arg#'InsertSubscriberDataArg'{'vlrCamelSubscriptionInfo'=patch(From, VlrCamel),
191 'sgsn-CAMEL-SubscriptionInfo'=patch(From, SgsnCamel)};
Harald Weltea68d96e2011-02-10 09:49:46 +0100192
193% HLR sends subscriber data to gsmSCF
Harald Welte29e589f2011-02-25 15:17:57 +0100194patch(From, #'AnyTimeSubscriptionInterrogationRes'{'camel-SubscriptionInfo'=Csi} = P) ->
195 P#'AnyTimeSubscriptionInterrogationRes'{'camel-SubscriptionInfo'=patch(From, Csi)};
Harald Weltea68d96e2011-02-10 09:49:46 +0100196
Harald Weltee77cb262011-02-25 17:06:30 +0100197patch(_From, asn1_NOVALUE) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100198 asn1_NOVALUE;
199
200% CAMEL related parsing
201
Harald Welte449a3172011-02-10 15:06:27 +0100202% this is part of the SRI Response (HLR->GMSC)
Harald Welte29e589f2011-02-25 15:17:57 +0100203patch(From, #'GmscCamelSubscriptionInfo'{'o-CSI'=Ocsi, 't-CSI'=Tcsi,
Harald Welte449a3172011-02-10 15:06:27 +0100204 'd-csi'=Dcsi} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100205 P#'GmscCamelSubscriptionInfo'{'o-CSI'=patch(From, Ocsi),
206 't-CSI'=patch(From, Tcsi),
207 'd-csi'=patch(From, Dcsi)};
Harald Welte449a3172011-02-10 15:06:27 +0100208
Harald Weltea68d96e2011-02-10 09:49:46 +0100209% this is part of the InsertSubscriberData HLR -> VLR
Harald Welte29e589f2011-02-25 15:17:57 +0100210patch(From, #'VlrCamelSubscriptionInfo'{'o-CSI'=Ocsi, 'mo-sms-CSI'=MoSmsCsi,
Harald Weltea68d96e2011-02-10 09:49:46 +0100211 'mt-sms-CSI'=MtSmsCsi, 'ss-CSI'=SsCsi} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100212 P#'VlrCamelSubscriptionInfo'{'o-CSI'=patch(From, Ocsi),
213 'mo-sms-CSI'=patch(From, MoSmsCsi),
214 'mt-sms-CSI'=patch(From, MtSmsCsi),
215 'ss-CSI'=patch(From, SsCsi)};
Harald Weltea68d96e2011-02-10 09:49:46 +0100216
217% this is part of the InsertSubscriberData HLR -> SGSN
Harald Welte29e589f2011-02-25 15:17:57 +0100218patch(From, #'SGSN-CAMEL-SubscriptionInfo'{'gprs-CSI'=GprsCsi,
Harald Weltea68d96e2011-02-10 09:49:46 +0100219 'mo-sms-CSI'=MoSmsCsi,
220 'mt-sms-CSI'=MtSmsCsi} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100221 P#'SGSN-CAMEL-SubscriptionInfo'{'gprs-CSI'=patch(From, GprsCsi),
222 'mo-sms-CSI'=patch(From, MoSmsCsi),
223 'mt-sms-CSI'=patch(From, MtSmsCsi)};
Harald Weltea68d96e2011-02-10 09:49:46 +0100224
225% this is part of the Anytime Subscription Interrogation Result HLR->gsmSCF
Harald Welte29e589f2011-02-25 15:17:57 +0100226patch(From, #'CAMEL-SubscriptionInfo'{'o-CSI'=Ocsi,
Harald Weltea68d96e2011-02-10 09:49:46 +0100227 'd-CSI'=Dcsi,
228 't-CSI'=Tcsi,
229 'vt-CSI'=Vtcsi,
230 %'tif-CSI'=Tifcsi,
231 'gprs-CSI'=GprsCsi,
232 'mo-sms-CSI'=MoSmsCsi,
233 'ss-CSI'=SsCsi,
234 'm-CSI'=Mcsi,
235 'mt-sms-CSI'=MtSmsCsi,
236 'mg-csi'=MgCsi,
237 'o-IM-CSI'=OimCsi,
238 'd-IM-CSI'=DimCsi,
239 'vt-IM-CSI'=VtImCsi} = P) ->
Harald Welte29e589f2011-02-25 15:17:57 +0100240 P#'CAMEL-SubscriptionInfo'{'o-CSI'=patch(From, Ocsi),
241 'd-CSI'=patch(From, Dcsi),
242 't-CSI'=patch(From, Tcsi),
243 'vt-CSI'=patch(From, Vtcsi),
244 'gprs-CSI'=patch(From, GprsCsi),
245 'mo-sms-CSI'=patch(From, MoSmsCsi),
246 'ss-CSI'=patch(From, SsCsi),
247 'm-CSI'=patch(From, Mcsi),
248 'mt-sms-CSI'=patch(From, MtSmsCsi),
249 'mg-csi'=patch(From, MgCsi),
250 'o-IM-CSI'=patch(From, OimCsi),
251 'd-IM-CSI'=patch(From, DimCsi),
252 'vt-IM-CSI'=patch(From, VtImCsi)};
Harald Weltea68d96e2011-02-10 09:49:46 +0100253
Harald Welte29e589f2011-02-25 15:17:57 +0100254patch(From, #'T-CSI'{'t-BcsmCamelTDPDataList'=TdpList} = P) ->
255 P#'T-CSI'{'t-BcsmCamelTDPDataList'=patch_tBcsmCamelTDPDataList(From, TdpList)};
256patch(From, #'M-CSI'{'gsmSCF-Address'=GsmScfAddr} = P) ->
257 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100258 P#'M-CSI'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100259patch(From, #'MG-CSI'{'gsmSCF-Address'=GsmScfAddr} = P) ->
260 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100261 P#'MG-CSI'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100262patch(From, #'O-CSI'{'o-BcsmCamelTDPDataList'=TdpList} = P) ->
263 P#'O-CSI'{'o-BcsmCamelTDPDataList'=patch_oBcsmCamelTDPDataList(From, TdpList)};
264patch(From, #'D-CSI'{'dp-AnalysedInfoCriteriaList'=List} = P) ->
265 P#'D-CSI'{'dp-AnalysedInfoCriteriaList'=patch_AnInfoCritList(From, List)};
266patch(From, #'SMS-CSI'{'sms-CAMEL-TDP-DataList'=TdpList} = P) ->
267 P#'SMS-CSI'{'sms-CAMEL-TDP-DataList'=patch_SmsCamelTDPDataList(From, TdpList)};
268patch(From, #'SS-CSI'{'ss-CamelData'=Sscd} = P) ->
269 P#'SS-CSI'{'ss-CamelData'=patch(From, Sscd)};
270patch(From, #'GPRS-CSI'{'gprs-CamelTDPDataList'=TdpList} = P) ->
271 P#'GPRS-CSI'{'gprs-CamelTDPDataList'=patch_GprsCamelTDPDataList(From, TdpList)};
272patch(From, #'SS-CamelData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
273 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100274 P#'SS-CamelData'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100275patch(From, #'O-BcsmCamelTDPData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
276 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100277 P#'O-BcsmCamelTDPData'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100278patch(From, #'T-BcsmCamelTDPData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
279 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Holger Hans Peter Freyther60e0fb22011-02-21 21:02:08 +0100280 P#'T-BcsmCamelTDPData'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100281patch(From, #'SMS-CAMEL-TDP-Data'{'gsmSCF-Address'=GsmScfAddr} = P) ->
282 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100283 P#'SMS-CAMEL-TDP-Data'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100284patch(From, #'GPRS-CamelTDPData'{'gsmSCF-Address'=GsmScfAddr} = P) ->
285 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100286 P#'GPRS-CamelTDPData'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100287patch(From, #'DP-AnalysedInfoCriterium'{'gsmSCF-Address'=GsmScfAddr} = P) ->
288 GsmScfAddrOut = patch_map_isdn_addr(From, GsmScfAddr, scf),
Harald Weltef9629642011-02-10 20:44:46 +0100289 P#'DP-AnalysedInfoCriterium'{'gsmSCF-Address'=GsmScfAddrOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100290patch(From, #'SubscriberInfo'{'locationInformation'=LocInformation} = P) ->
291 P#'SubscriberInfo'{'locationInformation'=patch(From, LocInformation)};
292patch(From, #'LocationInformation'{'vlr-number'=VlrNumber} = P) ->
293 VlrNumberOut = patch_map_isdn_addr(From, VlrNumber, vlr),
Holger Hans Peter Freyther016e3062011-02-21 22:04:38 +0100294 P#'LocationInformation'{'vlr-number'=VlrNumberOut};
Harald Welte29e589f2011-02-25 15:17:57 +0100295patch(From, #'MO-ForwardSM-Arg'{'sm-RP-DA'=SC} = P) ->
296 NewSC = patch_scaddr(From, SC),
Holger Hans Peter Freythere86edbd2011-02-22 23:24:55 +0100297 P#'MO-ForwardSM-Arg'{'sm-RP-DA'=NewSC};
Holger Hans Peter Freyther016e3062011-02-21 22:04:38 +0100298
Harald Welte29e589f2011-02-25 15:17:57 +0100299patch(_From, Default) ->
Harald Weltec7523622011-02-10 14:42:31 +0100300 Default.
Harald Weltea68d96e2011-02-10 09:49:46 +0100301
Holger Hans Peter Freythere86edbd2011-02-22 23:24:55 +0100302%rewrite the serviceCentreAddressDA
Harald Welte29e589f2011-02-25 15:17:57 +0100303patch_scaddr(From, {serviceCentreAddressDA,Ar}) ->
304 NewAddr = patch_map_isdn_addr(From, Ar, smsCDA),
Holger Hans Peter Freythere86edbd2011-02-22 23:24:55 +0100305 {serviceCentreAddressDA,NewAddr};
Harald Weltee77cb262011-02-25 17:06:30 +0100306patch_scaddr(_From, Default) ->
Holger Hans Peter Freythere86edbd2011-02-22 23:24:55 +0100307 Default.
308
Harald Welte29e589f2011-02-25 15:17:57 +0100309patch_oBcsmCamelTDPDataList(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100310 % we reverse the origianl list, as the tail recursive _acc function
311 % will invert the order of components again
Harald Welte29e589f2011-02-25 15:17:57 +0100312 patch_oBcsmCamelTDPDataList_acc(From, lists:reverse(List), []).
Harald Weltee77cb262011-02-25 17:06:30 +0100313patch_oBcsmCamelTDPDataList_acc(_From, [], NewList) -> NewList;
Harald Welte29e589f2011-02-25 15:17:57 +0100314patch_oBcsmCamelTDPDataList_acc(From, [TdpData|Tail], NewList) ->
315 NewTdpData = patch(From, TdpData#'O-BcsmCamelTDPData'{}),
316 patch_oBcsmCamelTDPDataList_acc(From, Tail, [NewTdpData|NewList]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100317
Harald Welte29e589f2011-02-25 15:17:57 +0100318patch_tBcsmCamelTDPDataList(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100319 % we reverse the origianl list, as the tail recursive _acc function
320 % will invert the order of components again
Harald Welte29e589f2011-02-25 15:17:57 +0100321 patch_tBcsmCamelTDPDataList_acc(From, lists:reverse(List), []).
Harald Weltee77cb262011-02-25 17:06:30 +0100322patch_tBcsmCamelTDPDataList_acc(_From, [], NewList) -> NewList;
Harald Welte29e589f2011-02-25 15:17:57 +0100323patch_tBcsmCamelTDPDataList_acc(From, [TdpData|Tail], NewList) ->
324 NewTdpData = patch(From, TdpData#'T-BcsmCamelTDPData'{}),
325 patch_tBcsmCamelTDPDataList_acc(From, Tail, [NewTdpData|NewList]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100326
Harald Welte29e589f2011-02-25 15:17:57 +0100327patch_AnInfoCritList(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100328 % we reverse the origianl list, as the tail recursive _acc function
329 % will invert the order of components again
Harald Welte29e589f2011-02-25 15:17:57 +0100330 patch_AnInfoCritList_acc(From, lists:reverse(List), []).
Harald Weltee77cb262011-02-25 17:06:30 +0100331patch_AnInfoCritList_acc(_From, [], NewList) -> NewList;
Harald Welte29e589f2011-02-25 15:17:57 +0100332patch_AnInfoCritList_acc(From, [Crit|Tail], NewList) ->
333 NewCrit = patch(From, Crit#'DP-AnalysedInfoCriterium'{}),
334 patch_AnInfoCritList_acc(From, Tail, [NewCrit|NewList]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100335
Harald Welte29e589f2011-02-25 15:17:57 +0100336patch_GprsCamelTDPDataList(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100337 % we reverse the origianl list, as the tail recursive _acc function
338 % will invert the order of components again
Harald Welte29e589f2011-02-25 15:17:57 +0100339 patch_GprsCamelTDPDataList_acc(From, lists:reverse(List), []).
340patch_GprsCamelTDPDataList_acc(_From, [], NewList) -> NewList;
341patch_GprsCamelTDPDataList_acc(From, [TdpData|Tail], NewList) ->
342 NewTdpData = patch(From, TdpData#'GPRS-CamelTDPData'{}),
343 patch_GprsCamelTDPDataList_acc(From, Tail, [NewTdpData|NewList]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100344
Harald Welte29e589f2011-02-25 15:17:57 +0100345patch_SmsCamelTDPDataList(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100346 % we reverse the origianl list, as the tail recursive _acc function
347 % will invert the order of components again
Harald Welte29e589f2011-02-25 15:17:57 +0100348 patch_SmsCamelTDPDataList_acc(From, lists:reverse(List), []).
Harald Weltee77cb262011-02-25 17:06:30 +0100349patch_SmsCamelTDPDataList_acc(_From, [], NewList) -> NewList;
Harald Welte29e589f2011-02-25 15:17:57 +0100350patch_SmsCamelTDPDataList_acc(From, [TdpData|Tail], NewList) ->
351 NewTdpData = patch(From, TdpData#'SMS-CAMEL-TDP-Data'{}),
352 patch_GprsCamelTDPDataList_acc(From, Tail, [NewTdpData|NewList]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100353
354
355
356% process the Argument of a particular MAP invocation
Harald Welte29e589f2011-02-25 15:17:57 +0100357process_component_arg(From, OpCode, Arg) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100358 case Arg of
359 asn1_NOVALUE -> Arg;
Harald Welte29e589f2011-02-25 15:17:57 +0100360 _ -> patch(From,Arg)
Harald Weltea68d96e2011-02-10 09:49:46 +0100361 end.
362
363% recurse over all components
Harald Welte2cc831f2011-02-10 18:36:02 +0100364handle_tcap_components(_From, asn1_NOVALUE) ->
Harald Welte17f64742011-02-10 18:29:59 +0100365 asn1_NOVALUE;
Harald Welte2cc831f2011-02-10 18:36:02 +0100366handle_tcap_components(From, List) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100367 % we reverse the origianl list, as the tail recursive _acc function
368 % will invert the order of components again
Harald Welte2cc831f2011-02-10 18:36:02 +0100369 handle_tcap_components_acc(From, lists:reverse(List), []).
370handle_tcap_components_acc(_From, [], NewComponents) -> NewComponents;
371handle_tcap_components_acc(From, [Component|Tail], NewComponents) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100372 case Component of
373 {basicROS, {Primitive, Body}} ->
374 io:format("handle component ~p primitive ~n", [Component]),
375 case Body of
376 % BEGIN
377 #'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
378 argument=Arg} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100379 NewArg = process_component_arg(From, OpCode, Arg),
Harald Weltea68d96e2011-02-10 09:49:46 +0100380 NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke'{argument=NewArg};
Harald Welteea193142011-02-10 15:40:36 +0100381 #'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100382 NewArg = process_component_arg(From, OpCode, Arg),
Harald Welteea193142011-02-10 15:40:36 +0100383 NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult'{result=R#'MapSpecificPDUs_begin_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
384 #'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100385 NewArg = process_component_arg(From, OpCode, Arg),
Harald Welteea193142011-02-10 15:40:36 +0100386 NewBody = Body#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast'{result=R#'MapSpecificPDUs_begin_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
Harald Weltea68d96e2011-02-10 09:49:46 +0100387 % END
388 #'MapSpecificPDUs_end_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
389 argument=Arg} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100390 NewArg = process_component_arg(From, OpCode, Arg),
Harald Weltea68d96e2011-02-10 09:49:46 +0100391 NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_basicROS_invoke'{argument=NewArg};
Harald Welteea193142011-02-10 15:40:36 +0100392 #'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100393 NewArg = process_component_arg(From, OpCode, Arg),
Harald Welteea193142011-02-10 15:40:36 +0100394 NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult'{result=R#'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
395 #'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100396 NewArg = process_component_arg(From, OpCode, Arg),
Harald Welteea193142011-02-10 15:40:36 +0100397 NewBody = Body#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast'{result=R#'MapSpecificPDUs_end_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
Harald Weltea68d96e2011-02-10 09:49:46 +0100398 % CONTINUE
399 #'MapSpecificPDUs_continue_components_SEQOF_basicROS_invoke'{opcode={local, OpCode},
400 argument=Arg} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100401 NewArg = process_component_arg(From, OpCode, Arg),
Harald Weltea68d96e2011-02-10 09:49:46 +0100402 NewBody = Body#'MapSpecificPDUs_continue_components_SEQOF_basicROS_invoke'{argument=NewArg};
Harald Welteea193142011-02-10 15:40:36 +0100403 #'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult'{result=#'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100404 NewArg = process_component_arg(From, OpCode, Arg),
Harald Weltef83e20e2011-05-23 12:41:14 +0200405 NewBody = Body#'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult'{result=R#'MapSpecificPDUs_continue_components_SEQOF_basicROS_returnResult_result'{result=NewArg}};
Harald Welteea193142011-02-10 15:40:36 +0100406 #'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast'{result=#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast_result'{opcode={local, OpCode}, result=Arg} = R} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100407 NewArg = process_component_arg(From, OpCode, Arg),
Harald Welteea193142011-02-10 15:40:36 +0100408 NewBody = Body#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast'{result=R#'MapSpecificPDUs_continue_components_SEQOF_returnResultNotLast_result'{result=NewArg}};
Harald Weltea68d96e2011-02-10 09:49:46 +0100409 _ ->
410 NewBody = Body
411 end,
412 %NewBody = setelement(5, Body, NewArg)
413 NewComponent = {basicROS, {Primitive, NewBody}};
414 _ ->
415 NewComponent = Component
416 end,
417 io:format("=> modified component ~p~n", [NewComponent]),
Harald Welte2cc831f2011-02-10 18:36:02 +0100418 handle_tcap_components_acc(From, Tail, [NewComponent|NewComponents]).
Harald Weltea68d96e2011-02-10 09:49:46 +0100419
420
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100421% Erlang asn1rt has this strange property that all incoming EXTERNAL types are
422% converted from the 1990 version into the 1994 version. The latter does not
423% preserve the encoding (octet string, single ASN1 type, ...). During encoding,
424% it then uses the OCTTET-STRING encoding, which is different from the MAP
425% customary single-ASN1-type format.
Harald Weltec506fe52011-02-10 13:09:44 +0100426asn1_EXTERNAL1994_fixup({'EXTERNAL', DirRef, IndRef, Data}) when is_list(Data);is_binary(Data) ->
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100427 % our trick is as follows: we simply convert back to 1990 format, and explicitly
428 % set the single-ASN1-type encoding. asn1rt:s 'enc_EXTERNAL'() will detect this
429 #'EXTERNAL'{'direct-reference' = DirRef, 'indirect-reference' = IndRef,
430 'encoding' = {'single-ASN1-type', Data}};
431asn1_EXTERNAL1994_fixup(Foo) ->
432 Foo.
433
434
Harald Welte2cc831f2011-02-10 18:36:02 +0100435handle_tcap_dialogue(_From, Foo = {'EXTERNAL', DirRef, IndRef, Data}) ->
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100436 asn1_EXTERNAL1994_fixup(Foo);
Harald Welte2cc831f2011-02-10 18:36:02 +0100437handle_tcap_dialogue(_From, Foo) ->
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100438 Foo.
439
Harald Weltea68d96e2011-02-10 09:49:46 +0100440
441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442% Actual mangling of the decoded MAP messages
443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Harald Welte2cc831f2011-02-10 18:36:02 +0100444mangle_map(From, {Type, TcapMsgDec}) ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100445 case {Type, TcapMsgDec} of
446 {'unidirectional', #'MapSpecificPDUs_unidirectional'{dialoguePortion=Dialg,
447 components=Components}} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100448 NewDialg = handle_tcap_dialogue(From, Dialg),
449 NewComponents = handle_tcap_components(From, Components),
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100450 NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_unidirectional'{dialoguePortion=NewDialg, components=NewComponents};
Harald Welte29c5f402011-02-10 13:24:49 +0100451 {'begin', #'MapSpecificPDUs_begin'{dialoguePortion=Dialg, components=Components}} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100452 NewDialg = handle_tcap_dialogue(From, Dialg),
453 NewComponents = handle_tcap_components(From, Components),
Harald Welte29c5f402011-02-10 13:24:49 +0100454 NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_begin'{dialoguePortion=NewDialg, components=NewComponents};
Harald Weltea68d96e2011-02-10 09:49:46 +0100455 {'continue', #'MapSpecificPDUs_continue'{dialoguePortion=Dialg, components=Components}} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100456 NewDialg = handle_tcap_dialogue(From, Dialg),
457 NewComponents = handle_tcap_components(From, Components),
Harald Welte9bc2e4a2011-02-10 12:40:31 +0100458 NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_continue'{dialoguePortion=NewDialg, components=NewComponents};
Harald Welte29c5f402011-02-10 13:24:49 +0100459 {'end', #'MapSpecificPDUs_end'{dialoguePortion=Dialg, components=Components}} ->
Harald Welte2cc831f2011-02-10 18:36:02 +0100460 NewDialg = handle_tcap_dialogue(From, Dialg),
461 NewComponents = handle_tcap_components(From, Components),
Harald Welte29c5f402011-02-10 13:24:49 +0100462 NewTcapMsgDec = TcapMsgDec#'MapSpecificPDUs_end'{dialoguePortion=NewDialg, components=NewComponents};
463 %{_, #'Abort'{reason=Reason} ->
Harald Weltea68d96e2011-02-10 09:49:46 +0100464 _ ->
465 NewTcapMsgDec = TcapMsgDec
466 end,
Harald Welte29c5f402011-02-10 13:24:49 +0100467 io:format("new TcapMsgDec (Type=~p) ~p~n", [Type, NewTcapMsgDec]),
Harald Weltea68d96e2011-02-10 09:49:46 +0100468 {Type, NewTcapMsgDec}.
469
Harald Weltef9629642011-02-10 20:44:46 +0100470
471% Configuration file has changed, re-generate internal data structures
472config_update() ->
473 % (re-)generate the MAP Address rewrite table
Harald Welte6009f6e2011-02-10 21:41:50 +0100474 {ok, MapRewriteTbl} = application:get_env(mgw_nat, map_rewrite_table),
Harald Weltef9629642011-02-10 20:44:46 +0100475 MapRewriteTblOut = generate_rewrite_table(MapRewriteTbl),
Harald Welte6009f6e2011-02-10 21:41:50 +0100476 application:set_env(mgw_nat, map_rewrite_table, MapRewriteTblOut),
Harald Welte9fe07292012-02-13 20:54:17 +0100477 % (re-)generate IMSI tree from text file
478 case application:get_env(mgw_nat, imsi_rewrite_file) of
479 {ok, ImsiListFile} ->
480 {ok, ImsiTree} = imsi_list:read_file(ImsiListFile),
Harald Weltefce6cf12012-02-20 07:56:16 +0100481 io:format("(Re)generated IMSI rewrite table: ~p entries~n",
Harald Welte6675c742013-02-06 09:14:37 +0100482 [imsi_list:num_entries(ImsiTree)]),
Harald Weltefce6cf12012-02-20 07:56:16 +0100483 application:set_env(mgw_nat, imsi_rewrite_tree, ImsiTree);
Harald Welte9fe07292012-02-13 20:54:17 +0100484 _ ->
485 ok
486 end,
Harald Weltea53a63a2012-02-13 22:10:33 +0100487 %{ok, MsrnPfxStp} = application:get_env(mgw_nat, msrn_pfx_stp),
488 %{ok, MsrnPfxMsc} = application:get_env(mgw_nat, msrn_pfx_msc),
489 %{ok, IntPfx} = application:get_env(mgw_nat, intern_pfx),
Harald Weltef9629642011-02-10 20:44:46 +0100490 ok.
491
492% Generate the full MAP address rewrite table
493generate_rewrite_table(List) when is_list(List) ->
494 generate_rewrite_table(List, []).
495generate_rewrite_table([], OutList) ->
496 io:format("(Re)generated MAP ISDN-Address rewrite table: ~p~n", [OutList]),
497 OutList;
498generate_rewrite_table([Head|Tail], OutList) ->
499 NewItem = generate_rewrite_entry(Head),
500 generate_rewrite_table(Tail, [NewItem|OutList]).
501
Harald Welted1410ae2011-02-25 21:33:34 +0100502% If a rewrite table entry is already fully-qualified, return it unmodified
503generate_rewrite_entry({Name, MscInt, StpInt, Msc, Stp}) ->
504 {Name, MscInt, StpInt, Msc, Stp};
Harald Weltef9629642011-02-10 20:44:46 +0100505% Generate a MAP Address rewrite table entry
506generate_rewrite_entry({Name, MscSideInt, StpSideInt}) ->
507 MscSideList = osmo_util:int2digit_list(MscSideInt),
508 StpSideList = osmo_util:int2digit_list(StpSideInt),
509 {Name, MscSideInt, StpSideInt, MscSideList, StpSideList}.
Harald Welte9fe07292012-02-13 20:54:17 +0100510
Harald Welte7bd1d4a2013-02-06 09:02:46 +0100511imsi_direction(sri_sm_res) ->
512 forward;
513imsi_direction(mo_fw_sm_arg) ->
514 reverse.
Harald Welte9fe07292012-02-13 20:54:17 +0100515
516% check if we need to rewrite the IMSI
Harald Welte7bd1d4a2013-02-06 09:02:46 +0100517patch_imsi(MsgType, from_msc, ImsiIn) ->
518 IsForward = imsi_direction(MsgType),
Harald Welte9fe07292012-02-13 20:54:17 +0100519 case application:get_env(mgw_nat, imsi_rewrite_tree) of
Harald Weltefce6cf12012-02-20 07:56:16 +0100520 {ok, ImsiTree} ->
Harald Welte9fe07292012-02-13 20:54:17 +0100521 % decode IMSI into list of digits
522 Imsi = map_codec:parse_map_addr(ImsiIn),
523 % rewrite prefix, if it matches
Harald Welte7bd1d4a2013-02-06 09:02:46 +0100524 case imsi_list:match_imsi(IsForward, ImsiTree, Imsi) of
Harald Weltefce6cf12012-02-20 07:56:16 +0100525 {ok, NewImsi} ->
Harald Welte9fe07292012-02-13 20:54:17 +0100526 map_codec:encode_map_tbcd(NewImsi);
Harald Weltefce6cf12012-02-20 07:56:16 +0100527 _ ->
Harald Welte9fe07292012-02-13 20:54:17 +0100528 ImsiIn
529 end;
530 _ ->
531 ImsiIn
532 end;
533patch_imsi(_, _, Imsi) ->
534 Imsi.