Add Erlang M2UA decoding and encoding routines
diff --git a/src/m2ua.hrl b/src/m2ua.hrl
new file mode 100644
index 0000000..26f10fc
--- /dev/null
+++ b/src/m2ua.hrl
@@ -0,0 +1,59 @@
+
+% RFC 3331 Section 3.1.3 Message Class
+-define(M2UA_MSGC_MGMT, 0). % Management Messages [IUA/M2UA/M3UA/SUA]
+-define(M2UA_MSGC_TRANSFER, 1). % Transfer Messages [M3UA]
+-define(M2UA_MSGC_SSNM, 2). % SS7 Signalling Network Management [M3UA/SUA]
+-define(M2UA_MSGC_ASPSM, 3). % ASP State Maintenance [IUA/M2UA/M3UA/SUA]
+-define(M2UA_MSGC_ASPTM, 4). % ASP Traffic Maintenance [IUA/M2UA/M3UA/SUA]
+-define(M2UA_MSGC_QPTM, 5). % Q.921/Q.931 Boundary Primitives Transport [IUA]
+-define(M2UA_MSGC_MAUP, 6). % MTP2 User Adaption [M2UA]
+-define(M2UA_MSGC_CONNLESS, 7). % Connectionless Messages [SUA]
+-define(M2UA_MSGC_CONN, 8). % Connection oriented messages [SUA]
+-define(M2UA_MSGC_RKM, 9). % Routing Key Management [M3UA]
+-define(M2UA_MSGC_IIM, 10). % Interface Identifier Management (M2UA)
+
+% RFC 3331 Section 3.1.4 Message Type
+-define(M2UA_MAUP_MSGT_RESERVED, 0).
+-define(M2UA_MAUP_MSGT_DATA, 1).
+-define(M2UA_MAUP_MSGT_EST_REQ, 2).
+-define(M2UA_MAUP_MSGT_EST_CONF, 3).
+-define(M2UA_MAUP_MSGT_REL_REQ, 4).
+-define(M2UA_MAUP_MSGT_REL_CONF, 5).
+-define(M2UA_MAUP_MSGT_REL_IND, 6).
+-define(M2UA_MAUP_MSGT_STATE_REQ, 7).
+-define(M2UA_MAUP_MSGT_STATE_CONF, 8).
+-define(M2UA_MAUP_MSGT_STATE_IND, 9).
+-define(M2UA_MAUP_MSGT_DATA_RETR_REQ, 10).
+-define(M2UA_MAUP_MSGT_DATA_RETR_CONF, 11).
+-define(M2UA_MAUP_MSGT_DATA_RETR_IND, 12).
+-define(M2UA_MAUP_MSGT_DATA_RETR_COMPL_IND, 13).
+-define(M2UA_MAUP_MSGT_CONG_IND, 14).
+-define(M2UA_MAUP_MSGT_DATA_ACK, 15).
+
+
+-define(M2UA_ASPSM_MSGT_UP, 0).
+-define(M2UA_ASPSM_MSGT_DOWN, 1).
+-define(M2UA_ASPSM_MSGT_BEAT, 2).
+-define(M2UA_ASPSM_MSGT_UP_ACK, 3).
+-define(M2UA_ASPSM_MSGT_DOWN_ACK, 5).
+-define(M2UA_ASPSM_MSGT_BEAT_ACK, 6).
+
+-define(M2UA_ASPTM_MSGT_ACTIVE, 1).
+-define(M2UA_ASPTM_MSGT_INACTIVE, 2).
+-define(M2UA_ASPTM_MSGT_ACTIVE_ACK, 3).
+-define(M2UA_ASPTM_MSGT_INACTIVE_ACK, 4).
+
+-define(M2UA_MGMT_MSGT_ERROR, 0).
+-define(M2UA_MGMT_MSGT_NOTIFY, 1).
+
+-define(M2UA_MGMT_IIM_REG_REQ, 1).
+-define(M2UA_MGMT_IIM_REG_RSP, 2).
+-define(M2UA_MGMT_IIM_DEREG_REQ, 3).
+-define(M2UA_MGMT_IIM_DEREG_RSP, 4).
+
+-record(m2ua_msg, {
+ msg_class,
+ msg_type,
+ parameters
+ }).
+
diff --git a/src/m2ua_codec.erl b/src/m2ua_codec.erl
new file mode 100644
index 0000000..262fbb1
--- /dev/null
+++ b/src/m2ua_codec.erl
@@ -0,0 +1,69 @@
+% RFC 3331 MTP2 User Adaption Layer coding / decoding
+
+% (C) 2011 by Harald Welte <laforge@gnumonks.org>
+%
+% 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 <http://www.gnu.org/licenses/>.
+
+-module(m2ua_codec).
+-author('Harald Welte <laforge@gnumonks.org>').
+-include("m2ua.hrl").
+
+-export([parse_m2ua_msg/1, encode_m2ua_msg/1]).
+
+% parse a binary chunk of options into an options proplist
+parse_m2ua_opts(<<>>, OptList) ->
+ OptList;
+parse_m2ua_opts(OptBin, OptList) ->
+ <<Tag:16/big, LengthIncHdr:16/big, Remain/binary>> = OptBin,
+ Length = LengthIncHdr - 4,
+ <<Value:Length/binary, NextOpts/binary>> = Remain,
+ NewOpt = {Tag, {Length, Value}},
+ parse_m2ua_opts(NextOpts, [NewOpt|OptList]).
+
+% parse a single M2UA message
+parse_m2ua_msgt(_, _, _, Remain) ->
+ parse_m2ua_opts(Remain, []).
+
+% parse a M2UA message binary into a record
+parse_m2ua_msg(DataBin) when is_binary(DataBin) ->
+ <<1:8, 0:8, MsgClass:8, MsgType:8, MsgLen:32/big, Remain/binary>> = DataBin,
+ Parsed = parse_m2ua_msgt(MsgClass, MsgType, MsgLen, Remain),
+ {ok, #m2ua_msg{msg_class = MsgClass, msg_type = MsgType, parameters = Parsed}}.
+
+
+
+% encode a single option
+encode_m2ua_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
+ LengthIncHdr = DataBinLen + 4,
+ <<OptNum:16/big, LengthIncHdr:16/big, DataBin/binary>>.
+
+% encode a list of options
+encode_m2ua_opts([], OptEnc) ->
+ list_to_binary(OptEnc);
+encode_m2ua_opts([CurOpt|OptPropList], OptEnc) ->
+ CurOptEnc = encode_m2ua_opt(CurOpt),
+ encode_m2ua_opts(OptPropList, list_to_binary([OptEnc, CurOptEnc])).
+
+
+% encode a particular message type
+encode_m2ua_msgt(MsgClass, MsgType, Params) ->
+ OptBin = encode_m2ua_opts(Params, <<>>),
+ MsgLenIncHdr = 4 + binary:byte_size(OptBin),
+ <<1:8, 0:8, MsgClass:8, MsgType:8, MsgLenIncHdr:32/big, OptBin/binary>>.
+
+% encode a message from record to binary
+encode_m2ua_msg(#m2ua_msg{msg_class = MsgClass, msg_type = MsgType, parameters = Params}) ->
+ encode_m2ua_msgt(MsgClass, MsgType, Params).