Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 1 | % GSM MAP codec wrapper functions |
| 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/>. |
Harald Welte | ef30ca8 | 2012-04-16 13:14:53 +0200 | [diff] [blame] | 19 | % |
| 20 | % Additional Permission under GNU AGPL version 3 section 7: |
| 21 | % |
| 22 | % If you modify this Program, or any covered work, by linking or |
| 23 | % combining it with runtime libraries of Erlang/OTP as released by |
| 24 | % Ericsson on http://www.erlang.org (or a modified version of these |
| 25 | % libraries), containing parts covered by the terms of the Erlang Public |
| 26 | % License (http://www.erlang.org/EPLICENSE), the licensors of this |
| 27 | % Program grant you additional permission to convey the resulting work |
| 28 | % without the need to license the runtime libraries of Erlang/OTP under |
| 29 | % the GNU Affero General Public License. Corresponding Source for a |
| 30 | % non-source form of such a combination shall include the source code |
| 31 | % for the parts of the runtime libraries of Erlang/OTP used as well as |
| 32 | % that of the covered work. |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 33 | |
| 34 | -module(map_codec). |
| 35 | -author('Harald Welte <laforge@gnumonks.org>'). |
Harald Welte | 21c6b94 | 2011-04-16 20:14:38 +0200 | [diff] [blame] | 36 | -include("map.hrl"). |
Harald Welte | 74368cc | 2011-02-09 21:41:36 +0100 | [diff] [blame] | 37 | -include_lib("osmo_ss7/include/isup.hrl"). |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 38 | |
Harald Welte | 0aa140b | 2011-02-09 23:15:22 +0100 | [diff] [blame] | 39 | -export([parse_tcap_msg/1, encode_tcap_msg/1]). |
Harald Welte | 74368cc | 2011-02-09 21:41:36 +0100 | [diff] [blame] | 40 | -export([parse_addr_string/1, encode_addr_string/1]). |
Harald Welte | aa3b39e | 2012-02-02 23:52:00 +0100 | [diff] [blame] | 41 | -export([parse_map_addr/1, encode_map_tbcd/1]). |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 42 | |
Harald Welte | 74368cc | 2011-02-09 21:41:36 +0100 | [diff] [blame] | 43 | -define(MAP_ADDR_NAT_UNKNOWN, 0). |
| 44 | -define(MAP_ADDR_NAT_INTERNATIONAL, 1). |
| 45 | -define(MAP_ADDR_NAT_NATIONAL, 2). |
| 46 | -define(MAP_ADDR_NAT_NETWORK_SPEC, 3). |
| 47 | -define(MAP_ADDR_NAT_SUBSCRIBER, 4). |
| 48 | -define(MAP_ADDR_NAT_RES, 5). |
| 49 | -define(MAP_ADDR_NAT_ABBREVIATED, 6). |
| 50 | -define(MAP_ADDR_NAT_RES_FOR_EXT, 7). |
| 51 | |
| 52 | % convert from MAP -> ISUP 'nature of address' |
| 53 | nature_map2isup(NatureMap) -> |
| 54 | case NatureMap of |
| 55 | ?MAP_ADDR_NAT_INTERNATIONAL -> ?ISUP_ADDR_NAT_INTERNATIONAL; |
| 56 | ?MAP_ADDR_NAT_NATIONAL -> ?ISUP_ADDR_NAT_NATIONAL; |
| 57 | ?MAP_ADDR_NAT_SUBSCRIBER -> ?ISUP_ADDR_NAT_SUBSCRIBER; |
| 58 | _ -> NatureMap |
| 59 | end. |
| 60 | |
| 61 | % convert from ISUP -> MAP 'nature of address' |
| 62 | nature_isup2map(NatureIsup) -> |
| 63 | case NatureIsup of |
| 64 | ?ISUP_ADDR_NAT_INTERNATIONAL -> ?MAP_ADDR_NAT_INTERNATIONAL; |
| 65 | ?ISUP_ADDR_NAT_NATIONAL -> ?MAP_ADDR_NAT_NATIONAL; |
| 66 | ?ISUP_ADDR_NAT_SUBSCRIBER -> ?MAP_ADDR_NAT_SUBSCRIBER; |
| 67 | _ -> NatureIsup |
| 68 | end. |
| 69 | |
Harald Welte | 4ae92fb | 2011-02-10 17:53:15 +0100 | [diff] [blame] | 70 | % Parse a TBCD-STRING |
| 71 | parse_map_tbcd(<<>>, DigitList) -> |
| 72 | DigitList; |
| 73 | parse_map_tbcd(BcdBin, DigitList) -> |
| 74 | <<Second:4, First:4, Remain/binary>> = BcdBin, |
| 75 | NewDigits = [First, Second], |
| 76 | parse_map_tbcd(Remain, DigitList ++ NewDigits). |
| 77 | parse_map_tbcd(ListBcd) when is_list(ListBcd) -> |
| 78 | BinBcd = list_to_binary(ListBcd), |
| 79 | parse_map_tbcd(BinBcd); |
| 80 | parse_map_tbcd(BinBcd) when is_binary(BinBcd) -> |
| 81 | parse_map_tbcd(BinBcd, []). |
| 82 | |
| 83 | % like parse_map_tbcd, but remove any trailing 0xF |
| 84 | parse_map_addr(Bcd) -> |
| 85 | DigitList = parse_map_tbcd(Bcd), |
| 86 | LastDigit = lists:last(DigitList), |
| 87 | if |
| 88 | LastDigit == 15 -> |
| 89 | lists:sublist(DigitList, length(DigitList)-1); |
| 90 | true -> |
| 91 | DigitList |
| 92 | end. |
| 93 | |
| 94 | encode_map_tbcd(BcdInt) when is_integer(BcdInt) -> |
| 95 | BcdList = osmo_util:int2digit_list(BcdInt), |
| 96 | encode_map_tbcd(BcdList); |
| 97 | encode_map_tbcd(BcdList) when is_list(BcdList) -> |
| 98 | encode_map_tbcd(BcdList, <<>>). |
| 99 | encode_map_tbcd([], Bin) -> |
| 100 | Bin; |
| 101 | encode_map_tbcd([First,Second|BcdList], Bin) -> |
| 102 | encode_map_tbcd(BcdList, <<Bin/binary, Second:4, First:4>>); |
| 103 | encode_map_tbcd([Last], Bin) -> |
| 104 | encode_map_tbcd([], <<Bin/binary, 15:4, Last:4>>). |
| 105 | |
| 106 | encode_map_addr(Bcd) -> |
| 107 | encode_map_tbcd(Bcd). |
| 108 | |
| 109 | |
Harald Welte | 74368cc | 2011-02-09 21:41:36 +0100 | [diff] [blame] | 110 | |
| 111 | parse_addr_string(AddrList) when is_list(AddrList) -> |
| 112 | parse_addr_string(list_to_binary(AddrList)); |
| 113 | parse_addr_string(AddrBin) when is_binary(AddrBin) -> |
| 114 | <<1:1, NatureMap:3, Numplan:4, Remain/binary>> = AddrBin, |
Harald Welte | 4ae92fb | 2011-02-10 17:53:15 +0100 | [diff] [blame] | 115 | PhoneNum = parse_map_addr(Remain), |
Harald Welte | 74368cc | 2011-02-09 21:41:36 +0100 | [diff] [blame] | 116 | NatureIsup = nature_map2isup(NatureMap), |
| 117 | #party_number{nature_of_addr_ind = NatureIsup, |
| 118 | numbering_plan = Numplan, |
| 119 | phone_number = PhoneNum}. |
| 120 | |
| 121 | encode_addr_string(#party_number{nature_of_addr_ind = NatureIsup, |
| 122 | numbering_plan = Numplan, |
| 123 | phone_number = PhoneNum}) -> |
| 124 | NatureMap = nature_isup2map(NatureIsup), |
Harald Welte | 5b14641 | 2011-02-10 17:57:09 +0100 | [diff] [blame] | 125 | PhoneBin = encode_map_addr(PhoneNum), |
Harald Welte | fc281c3 | 2011-02-09 22:39:08 +0100 | [diff] [blame] | 126 | Bin = <<1:1, NatureMap:3, Numplan:4, PhoneBin/binary>>, |
| 127 | binary_to_list(Bin). |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 128 | |
| 129 | parse_tcap_msg(MsgBin) when is_binary(MsgBin) -> |
Harald Welte | d08ea8d | 2011-02-09 23:13:48 +0100 | [diff] [blame] | 130 | Msg = binary_to_list(MsgBin), |
| 131 | parse_tcap_msg(Msg); |
| 132 | parse_tcap_msg(Msg) when is_list(Msg) -> |
| 133 | case asn1rt:decode('map', 'MapSpecificPDUs', Msg) of |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 134 | {ok, {Type, TcapMsgDec}} -> |
Harald Welte | 21c6b94 | 2011-04-16 20:14:38 +0200 | [diff] [blame] | 135 | fixup_dialogue({Type, TcapMsgDec}); |
Harald Welte | 268c572 | 2011-02-09 14:38:15 +0100 | [diff] [blame] | 136 | Error -> |
| 137 | Error |
| 138 | end. |
| 139 | |
Harald Welte | 21c6b94 | 2011-04-16 20:14:38 +0200 | [diff] [blame] | 140 | % Extract the dialoguePortion and feed it through external_1990ify/1 |
| 141 | fixup_dialogue({'begin', Beg = #'MapSpecificPDUs_begin'{dialoguePortion=Dia}}) -> |
| 142 | {'begin', Beg#'MapSpecificPDUs_begin'{dialoguePortion = external_1990ify(Dia)}}; |
| 143 | fixup_dialogue({'end', Beg = #'MapSpecificPDUs_end'{dialoguePortion=Dia}}) -> |
| 144 | {'end', Beg#'MapSpecificPDUs_end'{dialoguePortion = external_1990ify(Dia)}}; |
| 145 | fixup_dialogue({'continue', Beg = #'MapSpecificPDUs_continue'{dialoguePortion=Dia}}) -> |
| 146 | {'continue', Beg#'MapSpecificPDUs_continue'{dialoguePortion = external_1990ify(Dia)}}; |
| 147 | fixup_dialogue({'unidirectional', Beg = #'MapSpecificPDUs_unidirectional'{dialoguePortion=Dia}}) -> |
| 148 | {'unidirectional', Beg#'MapSpecificPDUs_unidirectional'{dialoguePortion = external_1990ify(Dia)}}; |
| 149 | fixup_dialogue(Default) -> |
| 150 | Default. |
| 151 | |
| 152 | % Take the EXTERNAL date type and convert from 1994-style to 1990 with 'single-ASN1-type' |
| 153 | external_1990ify({'EXTERNAL', {syntax, DirRef}, IndirRef, Data}) when is_list(Data); is_binary(Data) -> |
| 154 | #'EXTERNAL'{'direct-reference' = DirRef, |
| 155 | 'indirect-reference' = IndirRef, |
| 156 | encoding = {'single-ASN1-type', Data}}; |
| 157 | external_1990ify(Default) -> |
| 158 | Default. |
| 159 | |
Harald Welte | 0aa140b | 2011-02-09 23:15:22 +0100 | [diff] [blame] | 160 | encode_tcap_msg({Type, TcapMsgDec}) -> |
| 161 | case asn1rt:encode('map', 'MapSpecificPDUs', {Type, TcapMsgDec}) of |
Harald Welte | d08ea8d | 2011-02-09 23:13:48 +0100 | [diff] [blame] | 162 | {ok, List} -> |
| 163 | list_to_binary(List); |
| 164 | Error -> |
| 165 | Error |
| 166 | end. |