aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp/test/snmp_test_mgr_misc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp/test/snmp_test_mgr_misc.erl')
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl792
1 files changed, 792 insertions, 0 deletions
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
new file mode 100644
index 0000000000..e6220f9241
--- /dev/null
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -0,0 +1,792 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% ts:run(snmp, snmp_agent_test, [batch]).
+%%
+-module(snmp_test_mgr_misc).
+
+%% API
+-export([start_link_packet/8, start_link_packet/9,
+ stop/1,
+ send_discovery_pdu/2,
+ send_pdu/2, send_msg/4, send_bytes/2,
+ error/2,
+ get_pdu/1, set_pdu/2, format_hdr/1]).
+
+%% internal exports
+-export([init_packet/10]).
+
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+%%----------------------------------------------------------------------
+%% The InHandler process will receive messages on the form {snmp_pdu, Pdu}.
+%%----------------------------------------------------------------------
+start_link_packet(InHandler,
+ AgentIp, UdpPort, TrapUdp,
+ VsnHdr, Version, Dir, BufSz) ->
+ start_link_packet(InHandler,
+ AgentIp, UdpPort, TrapUdp,
+ VsnHdr, Version, Dir, BufSz,
+ false).
+
+start_link_packet(InHandler,
+ AgentIp, UdpPort, TrapUdp,
+ VsnHdr, Version, Dir, BufSz,
+ Dbg) when is_integer(UdpPort) ->
+ Args = [self(), InHandler,
+ AgentIp, UdpPort, TrapUdp,
+ VsnHdr, Version, Dir, BufSz,
+ Dbg],
+ proc_lib:start_link(?MODULE, init_packet, Args).
+
+stop(Pid) ->
+ Pid ! {stop, self()},
+ receive
+ {Pid, stopped} -> ok
+ end.
+
+
+send_discovery_pdu(Pdu, PacketPid) when is_record(Pdu, pdu) ->
+ PacketPid ! {send_discovery_pdu, self(), Pdu},
+ await_discovery_response_pdu().
+
+await_discovery_response_pdu() ->
+ receive
+ {discovery_response, Reply} ->
+ Reply
+ end.
+
+
+send_pdu(Pdu, PacketPid) when is_record(Pdu, pdu) ->
+ PacketPid ! {send_pdu, Pdu}.
+
+send_msg(Msg, PacketPid, Ip, Udp) when is_record(Msg, message) ->
+ PacketPid ! {send_msg, Msg, Ip, Udp}.
+
+send_bytes(Bytes, PacketPid) ->
+ PacketPid ! {send_bytes, Bytes}.
+
+%%--------------------------------------------------
+%% The SNMP encode/decode process
+%%--------------------------------------------------
+init_packet(Parent, SnmpMgr,
+ AgentIp, UdpPort, TrapUdp,
+ VsnHdr, Version, Dir, BufSz, DbgOptions) ->
+ put(sname, mgr_misc),
+ init_debug(DbgOptions),
+ {ok, UdpId} = gen_udp:open(TrapUdp, [{recbuf,BufSz},{reuseaddr, true}]),
+ put(msg_id, 1),
+ proc_lib:init_ack(Parent, self()),
+ init_usm(Version, Dir),
+ packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []).
+
+init_debug(Dbg) when is_atom(Dbg) ->
+ put(debug,Dbg),
+ put(verbosity,silence);
+ %% put(verbosity,trace);
+init_debug(DbgOptions) when is_list(DbgOptions) ->
+ case lists:keysearch(debug, 1, DbgOptions) of
+ {value, {_, Dbg}} when is_atom(Dbg) ->
+ put(debug, Dbg);
+ _ ->
+ put(debug, false)
+ end,
+ case lists:keysearch(verbosity, 1, DbgOptions) of
+ {value, {_, Ver}} when is_atom(Ver) ->
+ put(verbosity, Ver);
+ _ ->
+ put(verbosity, silence)
+ end,
+ ok.
+
+
+packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, MsgData) ->
+ receive
+ {send_discovery_pdu, From, Pdu} ->
+ d("packet_loop -> received send_discovery_pdu with"
+ "~n From: ~p"
+ "~n Pdu: ~p", [From, Pdu]),
+ case mk_discovery_msg(Version, Pdu, VsnHdr, "") of
+ error ->
+ ok;
+ {M, B} when is_list(B) ->
+ put(discovery, {M, From}),
+ display_outgoing_message(M),
+ udp_send(UdpId, AgentIp, UdpPort, B)
+ end,
+ packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []);
+
+ {send_pdu, Pdu} ->
+ d("packet_loop -> received send_pdu with"
+ "~n Pdu: ~p", [Pdu]),
+ case mk_msg(Version, Pdu, VsnHdr, MsgData) of
+ error ->
+ ok;
+ B when is_list(B) ->
+ udp_send(UdpId, AgentIp, UdpPort, B)
+ end,
+ packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
+
+ {send_msg, Msg, Ip, Udp} ->
+ d("packet_loop -> received send_msg with"
+ "~n Msg: ~p"
+ "~n Ip: ~p"
+ "~n Udp: ~p", [Msg,Ip,Udp]),
+ case catch snmp_pdus:enc_message(Msg) of
+ {'EXIT', Reason} ->
+ error("Encoding error:"
+ "~n Msg: ~w"
+ "~n Reason: ~w",[Msg, Reason]);
+ B when is_list(B) ->
+ udp_send(UdpId, Ip, Udp, B)
+ end,
+ packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
+ {udp, UdpId, Ip, UdpPort, Bytes} ->
+ d("packet_loop -> received udp with"
+ "~n UdpId: ~p"
+ "~n Ip: ~p"
+ "~n UdpPort: ~p"
+ "~n sz(Bytes): ~p", [UdpId, Ip, UdpPort, sz(Bytes)]),
+ MsgData3 = handle_udp_packet(Version, erase(discovery),
+ UdpId, Ip, UdpPort, Bytes,
+ SnmpMgr, AgentIp),
+ packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,
+ MsgData3);
+ {send_bytes, B} ->
+ d("packet_loop -> received send_bytes with"
+ "~n sz(B): ~p", [sz(B)]),
+ udp_send(UdpId, AgentIp, UdpPort, B),
+ packet_loop(SnmpMgr,UdpId,AgentIp,UdpPort,VsnHdr,Version,[]);
+ {stop, Pid} ->
+ d("packet_loop -> received stop from ~p", [Pid]),
+ gen_udp:close(UdpId),
+ Pid ! {self(), stopped},
+ exit(normal);
+ Other ->
+ d("packet_loop -> received unknown"
+ "~n ~p", [Other]),
+ exit({snmp_packet_got_other, Other})
+ end.
+
+
+handle_udp_packet(_V, undefined,
+ UdpId, Ip, UdpPort,
+ Bytes, SnmpMgr, AgentIp) ->
+ M = (catch snmp_pdus:dec_message_only(Bytes)),
+ MsgData3 =
+ case M of
+ Message when Message#message.version =:= 'version-3' ->
+ d("handle_udp_packet -> version 3"),
+ case catch handle_v3_msg(Bytes, Message) of
+ {ok, NewData, MsgData2} ->
+ Msg = Message#message{data = NewData},
+ case SnmpMgr of
+ {pdu, Pid} ->
+ Pdu = get_pdu(Msg),
+ d("packet_loop -> "
+ "send pdu to manager (~w): ~p", [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("packet_loop -> "
+ "send msg to manager (~w): ~p", [Pid, Msg]),
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end,
+ MsgData2;
+ {error, Reason, B} ->
+ udp_send(UdpId, AgentIp, UdpPort, B),
+ error("Decoding error. Auto-sending Report.\n"
+ "Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Reason, UdpPort, Ip]),
+ [];
+ {error, Reason} ->
+ error("Decoding error. "
+ "Bytes: ~w ~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Bytes, Reason, UdpPort, Ip]),
+ []
+ end;
+ Message when is_record(Message, message) ->
+ %% v1 or v2c
+ d("handle_udp_packet -> version v1 or v2c"),
+ case catch snmp_pdus:dec_pdu(Message#message.data) of
+ Pdu when is_record(Pdu, pdu) ->
+ case SnmpMgr of
+ {pdu, Pid} ->
+ d("handle_udp_packet -> "
+ "send pdu to manager (~w): ~p",
+ [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_udp_packet -> "
+ "send pdu-msg to manager (~w): ~p",
+ [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end;
+ Pdu when is_record(Pdu, trappdu) ->
+ case SnmpMgr of
+ {pdu, Pid} ->
+ d("handle_udp_packet -> "
+ "send trap to manager (~w): ~p",
+ [Pid, Pdu]),
+ Pid ! {snmp_pdu, Pdu};
+ {msg, Pid} ->
+ d("handle_udp_packet -> "
+ "send trap-msg to manager (~w): ~p",
+ [Pid, Pdu]),
+ Msg = Message#message{data = Pdu},
+ Pid ! {snmp_msg, Msg, Ip, UdpPort}
+ end;
+ Reason ->
+ error("Decoding error. "
+ "Bytes: ~w ~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Bytes, Reason, UdpPort, Ip])
+ end,
+ [];
+ Reason ->
+ error("Decoding error. Bytes: ~w ~n Reason: ~w "
+ "(UDPport: ~w, Ip: ~w)",
+ [Bytes, Reason, UdpPort, Ip]),
+ []
+ end,
+ MsgData3;
+handle_udp_packet(V, {DiscoReqMsg, From}, _UdpId, _Ip, _UdpPort,
+ Bytes, _, _AgentIp) ->
+ DiscoRspMsg = (catch snmp_pdus:dec_message(Bytes)),
+ display_incomming_message(DiscoRspMsg),
+ _Reply = (catch check_discovery_result(V, DiscoReqMsg, DiscoRspMsg)),
+ case (catch check_discovery_result(V, DiscoReqMsg, DiscoRspMsg)) of
+ {ok, AgentEngineID} when is_list(AgentEngineID) ->
+ %% Ok, step 1 complete, now for step 2
+ %% Which we skip for now
+ OK = {ok, AgentEngineID},
+ From ! {discovery_response, OK},
+ [];
+ Error ->
+ From ! {discovery_response, Error},
+ []
+ end.
+
+
+%% This function assumes that the agent and the manager (thats us)
+%% has the same version.
+check_discovery_result('version-3', DiscoReqMsg, DiscoRspMsg) ->
+ ReqMsgID = getMsgID(DiscoReqMsg),
+ RspMsgID = getMsgID(DiscoRspMsg),
+ check_msgID(ReqMsgID, RspMsgID),
+ ReqRequestId = getRequestId('version-3', DiscoReqMsg),
+ RspRequestId = getRequestId('version-3', DiscoRspMsg),
+ check_requestId(ReqRequestId, RspRequestId),
+ {ok, getMsgAuthEngineID(DiscoRspMsg)};
+check_discovery_result(Version, DiscoReqMsg, DiscoRspMsg) ->
+ ReqRequestId = getRequestId(Version, DiscoReqMsg),
+ RspRequestId = getRequestId(Version, DiscoRspMsg),
+ check_requestId(ReqRequestId, RspRequestId),
+ {ok, getSysDescr(DiscoRspMsg)}.
+
+check_msgID(ID, ID) ->
+ ok;
+check_msgID(ReqMsgID, RspMsgID) ->
+ throw({error, {invalid_msgID, ReqMsgID, RspMsgID}}).
+
+check_requestId(Id,Id) ->
+ ok;
+check_requestId(ReqRequestId, RspRequestId) ->
+ throw({error, {invalid_requestId, ReqRequestId, RspRequestId}}).
+
+getMsgID(M) when is_record(M, message) ->
+ (M#message.vsn_hdr)#v3_hdr.msgID.
+
+getRequestId('version-3',M) when is_record(M, message) ->
+ ((M#message.data)#scopedPdu.data)#pdu.request_id;
+getRequestId(_Version,M) when is_record(M, message) ->
+ (M#message.data)#pdu.request_id;
+getRequestId(Version,M) ->
+ io:format("************* ERROR ****************"
+ "~n Version: ~w"
+ "~n M: ~w~n", [Version,M]),
+ throw({error, {unknown_request_id, Version, M}}).
+
+getMsgAuthEngineID(M) when is_record(M, message) ->
+ SecParams1 = (M#message.vsn_hdr)#v3_hdr.msgSecurityParameters,
+ SecParams2 = snmp_pdus:dec_usm_security_parameters(SecParams1),
+ SecParams2#usmSecurityParameters.msgAuthoritativeEngineID.
+
+getSysDescr(M) when is_record(M, message) ->
+ getSysDescr((M#message.data)#pdu.varbinds);
+getSysDescr([]) ->
+ not_found;
+getSysDescr([#varbind{oid = [1,3,6,1,2,1,1,1], value = Value}|_]) ->
+ Value;
+getSysDescr([#varbind{oid = [1,3,6,1,2,1,1,1,0], value = Value}|_]) ->
+ Value;
+getSysDescr([_|T]) ->
+ getSysDescr(T).
+
+handle_v3_msg(Packet, #message{vsn_hdr = V3Hdr, data = Data}) ->
+ d("handle_v3_msg -> entry"),
+ %% Code copied from snmp_mpd.erl
+ #v3_hdr{msgID = MsgId, msgFlags = MsgFlags,
+ msgSecurityModel = MsgSecurityModel,
+ msgSecurityParameters = SecParams} = V3Hdr,
+ SecModule = get_security_module(MsgSecurityModel),
+ d("handle_v3_msg -> SecModule: ~p", [SecModule]),
+ SecLevel = hd(MsgFlags) band 3,
+ d("handle_v3_msg -> SecLevel: ~p", [SecLevel]),
+ IsReportable = snmp_misc:is_reportable(MsgFlags),
+ SecRes = (catch SecModule:process_incoming_msg(list_to_binary(Packet),
+ Data,SecParams,SecLevel)),
+ {_SecEngineID, SecName, ScopedPDUBytes, SecData, _} =
+ check_sec_module_result(SecRes, V3Hdr, Data, IsReportable),
+ case (catch snmp_pdus:dec_scoped_pdu(ScopedPDUBytes)) of
+ ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
+ {ok, ScopedPDU, {MsgId, SecName, SecData}};
+ {'EXIT', Reason} ->
+ throw({error, Reason});
+ Error ->
+ throw({error, {scoped_pdu_decode_failed, Error}})
+ end;
+handle_v3_msg(_Packet, BadMessage) ->
+ throw({error, bad_message, BadMessage}).
+
+get_security_module(?SEC_USM) ->
+ snmpa_usm;
+get_security_module(SecModel) ->
+ throw({error, {unknown_sec_model, SecModel}}).
+
+check_sec_module_result(Res, V3Hdr, Data, IsReportable) ->
+ d("check_sec_module_result -> entry with"
+ "~n Res: ~p", [Res]),
+ case Res of
+ {ok, X} ->
+ X;
+ {error, Reason, []} ->
+ throw({error, {securityError, Reason}});
+ {error, Reason, ErrorInfo} when IsReportable == true ->
+ #v3_hdr{msgID = MsgID, msgSecurityModel = MsgSecModel} = V3Hdr,
+ case generate_v3_report_msg(MsgID, MsgSecModel, Data, ErrorInfo) of
+ error ->
+ throw({error, {securityError, Reason}});
+ Packet ->
+ throw({error, {securityError, Reason}, Packet})
+ end;
+ {error, Reason, _} ->
+ throw({error, {securityError, Reason}});
+ Else ->
+ throw({error, {securityError, Else}})
+ end.
+
+generate_v3_report_msg(_MsgID, _MsgSecurityModel, Data, ErrorInfo) ->
+ d("generate_v3_report_msg -> entry with"
+ "~n ErrorInfo: ~p", [ErrorInfo]),
+ {Varbind, SecName, Opts} = ErrorInfo,
+ ReqId =
+ if is_record(Data, scopedPdu) -> (Data#scopedPdu.data)#pdu.request_id;
+ true -> 0
+ end,
+ Pdu = #pdu{type = report, request_id = ReqId,
+ error_status = noError, error_index = 0,
+ varbinds = [Varbind]},
+ SecLevel = snmp_misc:get_option(securityLevel, Opts, 0),
+ SnmpEngineID = snmp_framework_mib:get_engine_id(),
+ ContextEngineID =
+ snmp_misc:get_option(contextEngineID, Opts, SnmpEngineID),
+ ContextName = snmp_misc:get_option(contextName, Opts, ""),
+ mk_msg('version-3', Pdu, {ContextName, SecName, SnmpEngineID,
+ ContextEngineID, SecLevel},
+ undefined).
+
+
+error(Format, Data) ->
+ io:format("*** Error ***~n"),
+ ok = io:format(Format, Data),
+ io:format("~n").
+
+
+mk_discovery_msg('version-3', Pdu, _VsnHdr, UserName) ->
+ ScopedPDU = #scopedPdu{contextEngineID = "",
+ contextName = "",
+ data = Pdu},
+ Bytes = snmp_pdus:enc_scoped_pdu(ScopedPDU),
+ MsgID = get(msg_id),
+ put(msg_id, MsgID+1),
+ UsmSecParams =
+ #usmSecurityParameters{msgAuthoritativeEngineID = "",
+ msgAuthoritativeEngineBoots = 0,
+ msgAuthoritativeEngineTime = 0,
+ msgUserName = UserName,
+ msgPrivacyParameters = "",
+ msgAuthenticationParameters = ""},
+ SecBytes = snmp_pdus:enc_usm_security_parameters(UsmSecParams),
+ PduType = Pdu#pdu.type,
+ Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = 1000,
+ msgFlags = snmp_misc:mk_msg_flags(PduType, 0),
+ msgSecurityModel = ?SEC_USM,
+ msgSecurityParameters = SecBytes},
+ Msg = #message{version = 'version-3', vsn_hdr = Hdr, data = Bytes},
+ case (catch snmp_pdus:enc_message_only(Msg)) of
+ {'EXIT', Reason} ->
+ error("Discovery encoding error: "
+ "~n Pdu: ~w"
+ "~n Reason: ~w",[Pdu, Reason]),
+ error;
+ L when is_list(L) ->
+ {Msg#message{data = ScopedPDU}, L}
+ end;
+mk_discovery_msg(Version, Pdu, {Com, _, _, _, _}, _UserName) ->
+ Msg = #message{version = Version, vsn_hdr = Com, data = Pdu},
+ case catch snmp_pdus:enc_message(Msg) of
+ {'EXIT', Reason} ->
+ error("Discovery encoding error:"
+ "~n Pdu: ~w"
+ "~n Reason: ~w",[Pdu, Reason]),
+ error;
+ L when is_list(L) ->
+ {Msg, L}
+ end.
+
+
+mk_msg('version-3', Pdu, {Context, User, EngineID, CtxEngineId, SecLevel},
+ MsgData) ->
+ d("mk_msg(version-3) -> entry with"
+ "~n Pdu: ~p"
+ "~n Context: ~p"
+ "~n User: ~p"
+ "~n EngineID: ~p"
+ "~n CtxEngineID: ~p"
+ "~n SecLevel: ~p",
+ [Pdu, Context, User, EngineID, CtxEngineId, SecLevel]),
+ %% Code copied from snmp_mpd.erl
+ {MsgId, SecName, SecData} =
+ if
+ is_tuple(MsgData) andalso (Pdu#pdu.type =:= 'get-response') ->
+ MsgData;
+ true ->
+ Md = get(msg_id),
+ put(msg_id, Md + 1),
+ {Md, User, []}
+ end,
+ ScopedPDU = #scopedPdu{contextEngineID = CtxEngineId,
+ contextName = Context,
+ data = Pdu},
+ ScopedPDUBytes = snmp_pdus:enc_scoped_pdu(ScopedPDU),
+
+ PduType = Pdu#pdu.type,
+ V3Hdr = #v3_hdr{msgID = MsgId,
+ msgMaxSize = 1000,
+ msgFlags = snmp_misc:mk_msg_flags(PduType, SecLevel),
+ msgSecurityModel = ?SEC_USM},
+ Message = #message{version = 'version-3', vsn_hdr = V3Hdr,
+ data = ScopedPDUBytes},
+ SecEngineID = case PduType of
+ 'get-response' -> snmp_framework_mib:get_engine_id();
+ _ -> EngineID
+ end,
+ case catch snmpa_usm:generate_outgoing_msg(Message, SecEngineID,
+ SecName, SecData, SecLevel) of
+ {'EXIT', Reason} ->
+ error("version-3 message encoding exit"
+ "~n Pdu: ~w"
+ "~n Reason: ~w",[Pdu, Reason]),
+ error;
+ {error, Reason} ->
+ error("version-3 message encoding error"
+ "~n Pdu: ~w"
+ "~n Reason: ~w",[Pdu, Reason]),
+ error;
+ Packet ->
+ Packet
+ end;
+mk_msg(Version, Pdu, {Com, _User, _EngineID, _Ctx, _SecLevel}, _SecData) ->
+ Msg = #message{version = Version, vsn_hdr = Com, data = Pdu},
+ case catch snmp_pdus:enc_message(Msg) of
+ {'EXIT', Reason} ->
+ error("~w encoding error"
+ "~n Pdu: ~w"
+ "~n Reason: ~w",[Version, Pdu, Reason]),
+ error;
+ B when is_list(B) ->
+ B
+ end.
+
+format_hdr(#message{version = 'version-3',
+ vsn_hdr = #v3_hdr{msgID = MsgId},
+ data = #scopedPdu{contextName = CName}}) ->
+ io_lib:format("v3, ContextName = \"~s\" Message ID = ~w\n",
+ [CName, MsgId]);
+format_hdr(#message{version = Vsn, vsn_hdr = Com}) ->
+ io_lib:format("~w, CommunityName = \"~s\"\n", [vsn(Vsn), Com]).
+
+vsn('version-1') -> v1;
+vsn('version-2') -> v2c.
+
+
+udp_send(UdpId, AgentIp, UdpPort, B) ->
+ case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of
+ {error,ErrorReason} ->
+ error("failed (error) sending message to ~p:~p: "
+ "~n ~p",[AgentIp, UdpPort, ErrorReason]);
+ {'EXIT',ExitReason} ->
+ error("failed (exit) sending message to ~p:~p:"
+ "~n ~p",[AgentIp, UdpPort, ExitReason]);
+ _ ->
+ ok
+ end.
+
+
+get_pdu(#message{version = 'version-3', data = #scopedPdu{data = Pdu}}) ->
+ Pdu;
+get_pdu(#message{data = Pdu}) ->
+ Pdu.
+
+set_pdu(Msg, RePdu) when Msg#message.version == 'version-3' ->
+ SP = (Msg#message.data)#scopedPdu{data = RePdu},
+ Msg#message{data = SP};
+set_pdu(Msg, RePdu) ->
+ Msg#message{data = RePdu}.
+
+
+init_usm('version-3', Dir) ->
+ ets:new(snmp_agent_table, [set, public, named_table]),
+ ets:insert(snmp_agent_table, {agent_mib_storage, persistent}),
+ snmpa_local_db:start_link(normal, Dir, [{verbosity,trace}]),
+ NameDb = snmpa_agent:db(snmpEngineID),
+ R = snmp_generic:variable_set(NameDb, "mgrEngine"),
+ io:format("~w:init_usm -> engine-id set result: ~p~n", [?MODULE,R]),
+ snmp_framework_mib:set_engine_boots(1),
+ snmp_framework_mib:set_engine_time(1),
+ snmp_user_based_sm_mib:reconfigure(Dir);
+init_usm(_Vsn, _Dir) ->
+ ok.
+
+
+display_incomming_message(M) ->
+ display_message("Incomming",M).
+
+display_outgoing_message(M) ->
+ display_message("Outgoing", M).
+
+display_message(Direction, M) when is_record(M, message) ->
+ io:format("~s SNMP message:~n", [Direction]),
+ V = M#message.version,
+ display_version(V),
+ display_hdr(V, M#message.vsn_hdr),
+ display_msg_data(V, Direction, M#message.data);
+display_message(Direction, M) ->
+ io:format("~s message unknown: ~n~p", [Direction, M]).
+
+display_version('version-3') ->
+ display_prop("Version",'SNMPv3');
+display_version(V) ->
+ display_prop("Version",V).
+
+display_hdr('version-3',H) ->
+ display_msgID(H#v3_hdr.msgID),
+ display_msgMaxSize(H#v3_hdr.msgMaxSize),
+ display_msgFlags(H#v3_hdr.msgFlags),
+ SecModel = H#v3_hdr.msgSecurityModel,
+ display_msgSecurityModel(SecModel),
+ display_msgSecurityParameters(SecModel,H#v3_hdr.msgSecurityParameters);
+display_hdr(_V,Community) ->
+ display_community(Community).
+
+display_community(Community) ->
+ display_prop("Community",Community).
+
+display_msgID(Id) ->
+ display_prop("msgID",Id).
+
+display_msgMaxSize(Size) ->
+ display_prop("msgMaxSize",Size).
+
+display_msgFlags([Flags]) ->
+ display_prop("msgFlags",Flags);
+display_msgFlags([]) ->
+ display_prop("msgFlags",no_value_to_display);
+display_msgFlags(Flags) ->
+ display_prop("msgFlags",Flags).
+
+display_msgSecurityModel(?SEC_USM) ->
+ display_prop("msgSecurityModel",'USM');
+display_msgSecurityModel(Model) ->
+ display_prop("msgSecurityModel",Model).
+
+display_msgSecurityParameters(?SEC_USM,Params) ->
+ display_usmSecurityParameters(Params);
+display_msgSecurityParameters(_Model,Params) ->
+ display_prop("msgSecurityParameters",Params).
+
+display_usmSecurityParameters(P) when is_list(P) ->
+ P1 = lists:flatten(P),
+ display_usmSecurityParameters(snmp_pdus:dec_usm_security_parameters(P1));
+display_usmSecurityParameters(P) when is_record(P,usmSecurityParameters) ->
+ ID = P#usmSecurityParameters.msgAuthoritativeEngineID,
+ display_msgAuthoritativeEngineID(ID),
+ Boots = P#usmSecurityParameters.msgAuthoritativeEngineBoots,
+ display_msgAuthoritativeEngineBoots(Boots),
+ Time = P#usmSecurityParameters.msgAuthoritativeEngineTime,
+ display_msgAuthoritativeEngineTime(Time),
+ Name = P#usmSecurityParameters.msgUserName,
+ display_msgUserName(Name),
+ SecParams = P#usmSecurityParameters.msgAuthenticationParameters,
+ display_msgAuthenticationParameters(SecParams),
+ PrivParams = P#usmSecurityParameters.msgPrivacyParameters,
+ display_msgPrivacyParameters(PrivParams);
+display_usmSecurityParameters(P) ->
+ display_prop("unknown USM sec paraams",P).
+
+display_msgAuthoritativeEngineID(ID) ->
+ display_prop("msgAuthoritativeEngineID",ID).
+
+display_msgAuthoritativeEngineBoots(V) ->
+ display_prop("msgAuthoritativeEngineBoots",V).
+
+display_msgAuthoritativeEngineTime(V) ->
+ display_prop("msgAuthoritativeEngineTime",V).
+
+display_msgUserName(V) ->
+ display_prop("msgUserName",V).
+
+display_msgAuthenticationParameters(V) ->
+ display_prop("msgAuthenticationParameters",V).
+
+display_msgPrivacyParameters(V) ->
+ display_prop("msgPrivacyParameters",V).
+
+display_msg_data('version-3',Direction,D) when is_record(D,scopedPdu) ->
+ display_scoped_pdu(Direction,D);
+display_msg_data(_Version,Direction,D) when is_record(D,pdu) ->
+ display_pdu(Direction,D);
+display_msg_data(_Version,_Direction,D) ->
+ display_prop("Unknown message data",D).
+
+display_scoped_pdu(Direction,P) ->
+ display_contextEngineID(P#scopedPdu.contextEngineID),
+ display_contextName(P#scopedPdu.contextName),
+ display_scoped_pdu_data(Direction,P#scopedPdu.data).
+
+display_contextEngineID(Id) ->
+ display_prop("contextEngineID",Id).
+
+display_contextName(Name) ->
+ display_prop("contextName",Name).
+
+display_scoped_pdu_data(Direction,D) when is_record(D,pdu) ->
+ display_pdu(Direction,D);
+display_scoped_pdu_data(Direction,D) when is_record(D,trappdu) ->
+ display_trappdu(Direction,D);
+display_scoped_pdu_data(_Direction,D) ->
+ display_prop("Unknown scoped pdu data",D).
+
+display_pdu(Direction, P) ->
+ io:format("~s PDU:~n", [Direction]),
+ display_type(P#pdu.type),
+ display_request_id(P#pdu.request_id),
+ display_error_status(P#pdu.error_status),
+ display_error_index(P#pdu.error_index),
+ display_varbinds(P#pdu.varbinds).
+
+display_type(T) ->
+ display_prop("Type",T).
+
+display_request_id(Id) ->
+ display_prop("Request id",Id).
+
+display_error_status(S) ->
+ display_prop("Error status",S).
+
+display_error_index(I) ->
+ display_prop("Error index",I).
+
+display_varbinds([H|T]) ->
+ display_prop_hdr("Varbinds"),
+ display_varbind(H),
+ display_varbinds(T);
+display_varbinds([]) ->
+ ok.
+
+display_varbind(V) when is_record(V,varbind) ->
+ display_oid(V#varbind.oid),
+ display_vtype(V#varbind.variabletype),
+ display_value(V#varbind.value),
+ display_org_index(V#varbind.org_index);
+display_varbind(V) ->
+ display_prop("\tVarbind",V).
+
+display_oid(V) ->
+ display_prop("\tOid",V).
+
+display_vtype(V) ->
+ display_prop("\t\tVariable type",V).
+
+display_value(V) ->
+ display_prop("\t\tValue",V).
+
+display_org_index(V) ->
+ display_prop("\t\tOrg index",V).
+
+display_trappdu(Direction,P) ->
+ io:format("~s TRAP-PDU:~n",[Direction]),
+ display_prop("TRAP-PDU",P).
+
+display_prop(S,no_value_to_display) ->
+ io:format("\t~s: ~n",[S]);
+display_prop(S,V) ->
+ io:format("\t~s: ~p~n",[S,V]).
+
+
+display_prop_hdr(S) ->
+ io:format("\t~s:~n",[S]).
+
+
+%%----------------------------------------------------------------------
+%% Debug
+%%----------------------------------------------------------------------
+
+sz(L) when is_list(L) ->
+ length(lists:flatten(L));
+sz(B) when is_binary(B) ->
+ size(B);
+sz(O) ->
+ {unknown_size, O}.
+
+d(F) -> d(F, []).
+d(F,A) -> d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n",
+ [format_timestamp(now())|A]);
+d(_,_F,_A) ->
+ ok.
+
+format_timestamp({_N1, _N2, N3} = Now) ->
+ {Date, Time} = calendar:now_to_datetime(Now),
+ {YYYY,MM,DD} = Date,
+ {Hour,Min,Sec} = Time,
+ FormatDate =
+ io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w",
+ [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]),
+ lists:flatten(FormatDate).
+