% GSM TS 08.08 / 3GPP TS 48.008 BSSMAP % (C) 2010 by Harald Welte % % All Rights Reserved % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU Affero General Public License as % published by the Free Software Foundation; either version 3 of the % License, or (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU Affero General Public License % along with this program. If not, see . % % Additional Permission under GNU AGPL version 3 section 7: % % If you modify this Program, or any covered work, by linking or % combining it with runtime libraries of Erlang/OTP as released by % Ericsson on https://www.erlang.org (or a modified version of these % libraries), containing parts covered by the terms of the Erlang Public % License (https://www.erlang.org/EPLICENSE), the licensors of this % Program grant you additional permission to convey the resulting work % without the need to license the runtime libraries of Erlang/OTP under % the GNU Affero General Public License. Corresponding Source for a % non-source form of such a combination shall include the source code % for the parts of the runtime libraries of Erlang/OTP used as well as % that of the covered work. -module(bssmap_codec). -author('Harald Welte '). -include("bssmap.hrl"). -export([parse_bssmap_msg/1, encode_bssmap_msg/1]). parse_bssmap_msg(<>) -> parse_bssmap_msgt(MsgType, Remain). parse_bssmap_msgt(MsgType, Msg) when is_integer(MsgType), is_binary(Msg) -> IeList = parse_ies(Msg, []), {bssmap_msg, MsgType, IeList}. parse_ies(<<>>, ParsedIeList) -> ParsedIeList; parse_ies(Msg, ParsedIeList) when is_binary(Msg) -> CurIe = binary:first(Msg), % Parse current IE and append it to list of Parsed IEs case is_tv_ie(CurIe) of true -> Res = parse_ie_tv(CurIe, Msg); false -> Res = parse_ie(CurIe, Msg) end, {ok, BytesConsumed, ParsedIe} = Res, {CurIe, Payload} = ParsedIe, DecodedIe = decode_ie(CurIe, Payload), ParsedIeList1 = ParsedIeList ++ [DecodedIe], %ParsedIeList1 = ParsedIeList ++ [ParsedIe], RemainMsg = binary:part(Msg, BytesConsumed, byte_size(Msg)-BytesConsumed), parse_ies(RemainMsg, ParsedIeList1). % check if this element is of TV type is_tv_ie(T) when T == ?BSSMAP_IE_NUMBER_OF_MSS; T == ?BSSMAP_IE_PERIODICITY; T == ?BSSMAP_IE_EXTD_RES_IND; T == ?BSSMAP_IE_INTERF_BAND_TO_USE; T == ?BSSMAP_IE_RR_CAUSE; T == ?BSSMAP_IE_DLCI; T == ?BSSMAP_IE_DOWNLINK_DTX_FLAG; T == ?BSSMAP_IE_RESPONSE_RQST; T == ?BSSMAP_IE_RES_IND_METHOD; T == ?BSSMAP_IE_CM_INFO_T1; T == ?BSSMAP_IE_CHOSEN_CHANNEL; T == ?BSSMAP_IE_CIPH_RESP_MODE; T == ?BSSMAP_IE_TRACE_TYPE; T == ?BSSMAP_IE_TRACE_REFERENCE; T == ?BSSMAP_IE_FORWARD_INDICATOR; T == ?BSSMAP_IE_CHOSEN_ENCR_ALG; T == ?BSSMAP_IE_CIRCUIT_POOL; T == ?BSSMAP_IE_TIME_INDICATION; T == ?BSSMAP_IE_CUR_CHAN_TYPE_1; T == ?BSSMAP_IE_QUEUEING_IND; T == ?BSSMAP_IE_SPEECH_VERSION; T == ?BSSMAP_IE_ASS_REQUIREMENT; T == ?BSSMAP_IE_EMLPP_PRIORITY; T == ?BSSMAP_IE_CONFIG_EVO_INDI; T == ?BSSMAP_IE_LSA_ACCESS_CTRL_SUPPR -> true; is_tv_ie(_T) -> false. % Parser for any non-TLV and non-TV IEs parse_ie(?BSSMAP_IE_CIRC_ID_CODE, Msg) -> <> = Msg, {ok, 3, {?BSSMAP_IE_CIRC_ID_CODE, Cic}}; parse_ie(?BSSMAP_IE_CONN_REL_RQSTED, Msg) -> <> = Msg, {ok, 1, {?BSSMAP_IE_CONN_REL_RQSTED, 1}}; parse_ie(?BSSMAP_IE_RES_AVAIL, Msg) -> <> = Msg, {ok, 9, {?BSSMAP_IE_RES_AVAIL, ResAvail}}; parse_ie(?BSSMAP_IE_TOT_RES_ACCESS, Msg) -> <> = Msg, {ok, 5, {?BSSMAP_IE_TOT_RES_ACCESS, ResAvail}}; parse_ie(?BSSMAP_IE_TALKER_FLAG, Msg) -> <> = Msg, {ok, 1, {?BSSMAP_IE_TALKER_FLAG, 1}}; % Default: Parser for TLV IE parse_ie(MsgType, Msg) -> <> = Msg, {ok, 2+Length, {MsgType, Value}}. % Parser for simple Tag-Value IE parse_ie_tv(IeType, Msg) -> <> = Msg, {ok, 2, {IeType, Par}}. % FIXME encode_bssmap_msg(_) -> ok. decode_ie(?BSSMAP_IE_CIRC_ID_CODE, <>) -> {circuit_id, Pcm, Ts}; decode_ie(?BSSMAP_IE_IMSI, Remain) -> {imsi, bin_bcd2str(Remain)}; decode_ie(?BSSMAP_IE_TMSI, <>) -> {tmsi, Tmsi}; decode_ie(?BSSMAP_IE_L3_HDR_INFO, <>) -> {l3_hdr_info, Pdisc, Tid}; decode_ie(?BSSMAP_IE_ENCR_INFO, <>) -> {encr_info, Algos, Key}; decode_ie(?BSSMAP_IE_CHANNEL_TYPE, <<_:4, Spdi:4, RateType:8, Remain/binary>>) -> {chan_type, Spdi, RateType, Remain}; decode_ie(?BSSMAP_IE_EXTD_RES_IND, Ri) -> <<_:6, Sm:1, Tarr:1>> = <>, {extended_ri, Sm, Tarr}; decode_ie(?BSSMAP_IE_TOT_RES_ACCESS, <>) -> {tot_res_access, NumFr, NumHr}; decode_ie(?BSSMAP_IE_CELL_ID, <<_Spare:4, Discr:4, Remain/binary>>) -> {cell_id, decode_cid_ie(Discr, Remain)}; decode_ie(?BSSMAP_IE_PRIORITY, <<_:1, Pci:1, Prio:4, Qa:1, Pvi:1>>) -> {priority, Pci, Prio, Qa, Pvi}; decode_ie(?BSSMAP_IE_CELL_ID_LIST, <<_Spare:4, Discr:4, Remain/binary>>) -> {cell_id_list, decode_cid_list(Discr, Remain, [])}; decode_ie(?BSSMAP_IE_DIAGNOSTIC, <>) -> {diagnostic, ErrPtr, BitPtr, MsgRecv}; decode_ie(?BSSMAP_IE_CHOSEN_CHANNEL, Int) -> <> = <>, {chosen_channel, Mode, Chan}; decode_ie(?BSSMAP_IE_MOBILE_IDENTITY, Data) -> % FIXME fixme; % Default: don't decode decode_ie(IeI, Data) -> {IeI, Data}. decode_cid_ie(?CELL_ID_WHOLE_GLOBAL, Remain) -> <> = Remain, [{mcc, [Mcc1, Mcc2, Mcc3]}, {mnc, [Mnc1, Mnc2, Mnc3]}, {lac, Lac}, {cid, Ci}]; decode_cid_ie(?CELL_ID_LAC_AND_CI, Remain) -> <> = Remain, [{lac, Lac}, {cid, Ci}]; decode_cid_ie(?CELL_ID_CI, Remain) -> <> = Remain, [{cid, Ci}]; decode_cid_ie(?CELL_ID_NO_CELL, _Remain) -> []; decode_cid_ie(?CELL_ID_UTRAN_PLMN_LAC_RNC, Remain) -> <> = Remain, [{mcc, [Mcc1, Mcc2, Mcc3]}, {mnc, [Mnc1, Mnc2, Mnc3]}, {lac, Lac}, {rnc_id, Rnc}]; decode_cid_ie(?CELL_ID_UTRAN_RNC, Remain) -> <> = Remain, [{rnc_id, Rnc}]; decode_cid_ie(?CELL_ID_UTRAN_LAC_RNC, Remain) -> <> = Remain, [{lac, Lac}, {rnc_id, Rnc}]. decode_cid_list(Discr, Data, List) -> case Discr of ?CELL_ID_WHOLE_GLOBAL -> Len = 7; ?CELL_ID_LAC_AND_CI -> Len = 4; ?CELL_ID_CI -> Len = 2; ?CELL_ID_NO_CELL -> Len = 0; ?CELL_ID_UTRAN_PLMN_LAC_RNC -> Len = 7; ?CELL_ID_UTRAN_RNC -> Len = 2; ?CELL_ID_UTRAN_LAC_RNC -> Len = 4 end, <> = Data, Elem = {cell_id, decode_cid_ie(Discr, Subset)}, decode_cid_list(Discr, Remain, List ++ [Elem]). bin_bcd2str(BcdBin) when is_binary(BcdBin) -> bin_bcd2str(BcdBin, []). bin_bcd2str(<<>>, List) -> List; bin_bcd2str(BcdBin, List) -> <> = BcdBin, Char = $0 + Nibble, bin_bcd2str(Remain, List ++ [Char]).