summaryrefslogtreecommitdiff
path: root/deps/netlink/src/netlink_codec.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/netlink/src/netlink_codec.erl')
-rw-r--r--deps/netlink/src/netlink_codec.erl214
1 files changed, 214 insertions, 0 deletions
diff --git a/deps/netlink/src/netlink_codec.erl b/deps/netlink/src/netlink_codec.erl
new file mode 100644
index 0000000..b611232
--- /dev/null
+++ b/deps/netlink/src/netlink_codec.erl
@@ -0,0 +1,214 @@
+%%% @author tony <tony@rogvall.se>
+%%% @copyright (C) 2013, tony
+%%% @doc
+%%% Encode / Decode of netlink messages
+%%% @end
+%%% Created : 21 May 2013 by tony <tony@rogvall.se>
+
+-module(netlink_codec).
+
+-export([encode_flags/2]).
+-export([decode_flags/2]).
+-export([encode_tlv/1, encode_tlv_list/1]).
+-export([decode_tlv/1, decode_tlv_list/1]).
+
+-export([decode/2]).
+-export([encode/2]).
+
+-compile(export_all).
+
+-include("netlink.hrl").
+-include("netl_codec.hrl").
+
+-define(ALIGNTO, 4).
+-define(ALIGNMASK, (?ALIGNTO-1)).
+-define(NLA_ALIGN(N), (((N)+?ALIGNMASK) band (bnot ?ALIGNMASK))).
+-define(NLA_PAD(N), ((?ALIGNTO-((N) band ?ALIGNMASK)) band
+ ?ALIGNMASK)).
+%% may need adjustment (NLA_ALIGN(sizeof(struct nlattr)))
+-define(NLA_HDRLEN, 4).
+%% -define(NLA_PAD(N), (ALIGN(N) - N)).
+
+%% prove that:
+%% ((N+3) band (bnot 3)) - N == (4 - (N band 3)) band 3
+%%
+
+encode_flags(Flags, Fun) ->
+ encode_flags(Flags, 0, Fun).
+
+encode_flags([], Mask, _Fun) -> Mask;
+encode_flags([Flag|Flags], Mask, Fun) ->
+ BitNum = Fun(Flag),
+ encode_flags(Flags, Mask+(1 bsl BitNum), Fun).
+
+
+decode_flags(Value, Fun) ->
+ decode_flags(0, Value, Fun).
+
+decode_flags(_I, 0, _Fun) -> [];
+decode_flags(I, Value, Fun) ->
+ Bit = (1 bsl I),
+ if Value band Bit =:= Bit ->
+ [Fun(I) | decode_flags(I+1, Value band (bnot Bit), Fun)];
+ true ->
+ decode_flags(I+1,Value,Fun)
+ end.
+
+decode_attr([{Ri,_Endian,Rv}|Ds], Fun) ->
+ [ Fun(Ri,Rv) | decode_attr(Ds, Fun)];
+decode_attr([], _Fun) ->
+ [].
+
+encode_tlv({Type0,Endian,Data}) ->
+ Payload = if is_list(Data) ->
+ encode_tlv_list(Data);
+ is_binary(Data) -> Data
+ end,
+ Type = if is_list(Data) ->
+ Type0 + 16#8000;
+ Endian =:= big ->
+ Type0 + 16#4000;
+ true ->
+ Type0
+ end,
+ Len = ?NLA_HDRLEN+byte_size(Payload),
+ Pad = ?NLA_PAD(Len),
+ <<Len:16/native-unsigned, Type:16/native-unsigned,
+ Payload/binary, 0:Pad/unit:8>>.
+
+encode_tlv_list(TLVs) ->
+ list_to_binary([encode_tlv(TLV) || TLV <- TLVs]).
+
+next_tlv(<<Len0:16/native-unsigned, _:16, Data/binary>>) ->
+ Len = Len0 - ?NLA_HDRLEN,
+ Pad = ?NLA_PAD(Len),
+ <<_:Len/binary, _:Pad/unit:8, Data1/binary>> = Data,
+ Data1.
+
+decode_tlv(<<Len0:16/native-unsigned, Type0:16/native-unsigned,
+ Rest/binary>>) ->
+ Len = Len0 - ?NLA_HDRLEN,
+ <<Payload:Len/binary, _/binary>> = Rest,
+ Type = Type0 band 16#3fff,
+ if Type0 band 16#8000 =:= 16#8000 ->
+ {Type, native, decode_tlv_list(Payload)};
+ Type0 band 16#4000 =:= 16#4000 ->
+ {Type, big, Payload};
+ true ->
+ {Type, native, Payload}
+ end.
+
+decode_tlv_list(<<>>) ->
+ [];
+decode_tlv_list(Data) ->
+ TLV = decode_tlv(Data),
+ Data1 = next_tlv(Data),
+ [TLV | decode_tlv_list(Data1)].
+
+
+decode(Part=
+ << Len:32/native-integer,
+ Type:16/native-integer,
+ Flags:16/native-integer,
+ Seq:32/native-integer,
+ Pid:32/native-integer,
+ Data/binary >>, Acc) ->
+ if Len >= byte_size(Part) ->
+ PayloadLen = Len - 16,
+ << Payload:PayloadLen/bytes, NextPart/binary >> = Data,
+ Msg = decode_(Type, Flags, Seq, Pid, Payload),
+ decode(NextPart, [Msg | Acc]);
+ true ->
+ decode(<<>>, [{ error, format} | Acc])
+ end;
+decode(_PadPart, Acc) ->
+ lists:reverse(Acc).
+
+decode_(Type,Flags,Seq,Pid,Payload) ->
+ MsgType = netl_codec:dec_nlmsg_type(Type),
+ FlagList = case msg_type(MsgType) of
+ new ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_new_flags/1);
+ get ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_get_flags/1);
+ _ ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_flags/1)
+ end,
+ MsgPayload = apply(netl_codec,
+ list_to_atom("dec_"++atom_to_list(MsgType)),
+ [{native,Payload}]),
+ H = #nlmsghdr { type=MsgType, flags=FlagList, seq=Seq, pid=Pid },
+ #nlmsg { hdr = H, data=MsgPayload }.
+
+encode(#nlmsghdr { type=MsgType, flags=FlagList, seq=Seq, pid=Pid },
+ MsgPayload ) ->
+ Type = netl_codec:enc_nlmsg_type(MsgType),
+ Flags = case msg_type(MsgType) of
+ new ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_new_flags/1);
+ get ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_get_flags/1);
+ _ ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_flags/1)
+ end,
+ Payload = apply(netl_codec,
+ list_to_atom("enc_"++atom_to_list(MsgType)),
+ [{native,MsgPayload}]),
+ N = byte_size(Payload),
+ Pad = ?NLA_PAD(N),
+ Len = 16 + Pad + N,
+ << Len:32/native-integer,
+ Type:16/native-integer,
+ Flags:16/native-integer,
+ Seq:32/native-integer,
+ Pid:32/native-integer,
+ Payload/binary,
+ 0:Pad/unit:8 >>.
+
+msg_type(Type) ->
+ case Type of
+ noop -> misc;
+ error -> misc;
+ done -> misc;
+ overrun -> misc;
+ newlink -> new;
+ dellink -> del;
+ getlink -> get;
+ setlink -> set;
+ newaddr -> new;
+ deladdr -> del;
+ getaddr -> get;
+ newroute -> new;
+ delroute -> del;
+ getroute -> get;
+ newneigh -> new;
+ delneigh -> del;
+ getneigh -> get;
+ newrule -> new;
+ delrule -> del;
+ getrule -> get;
+ newdisc -> new;
+ delqdisc -> del;
+ getqdisc -> get;
+ newtclass -> new;
+ deltclass -> del;
+ gettclass -> get;
+ newtfilter -> new;
+ deltfilter -> del;
+ gettfilter -> get;
+ newaction -> new;
+ delaction -> del;
+ getaction -> get;
+ newprefix -> new;
+ getmulticast -> get;
+ getanycast -> get;
+ newneightbl -> new;
+ getneightbl -> get;
+ setneightbl -> set;
+ newnduseropt -> new;
+ newaddrlabel -> new;
+ deladdrlabel -> del;
+ getaddrlabel -> get;
+ getdcb -> get;
+ setdcb -> set
+ end.